What this proves, and what it does not
Two validation layers, stated separately. First: a JavaScript implementation and a second Python implementation of the same CPM algorithm, both written by the same author, agree on all 22189 field comparisons the harness runs across 233 fixtures, covering calendars, all four relationship types, leads and lags, constraints, both P6 scheduling modes, in-progress work, out-of-sequence progress, the retained-logic pass-through, the unexpired part of a lag off started and completed work, the Must Finish By (applied under "opened projects" too), suspend and resume dates, links between completed activities, constraints dated on time the calendar does not work, As Late As Possible work, external early start and late finish dates, the dates a milestone prints, zero-length tasks and progress override's finish links, the hours pass on P6's own hours, resource dependent work on its resources' calendars, the float and critical set P6 prints, cycle refusal and far-future date arithmetic. None is skipped: the 100 comparisons skipped through v2.10.0, on the two signed free-float fields of completed activities where neither implementation emitted them, run since both began emitting 0 there, and the 58 one-sided skips that were a real port gap closed when the has-successors branch was ported. Counted, agreement is 22189 of 22189. Two ports by one author catch transcription and refactor drift; they cannot catch a shared misreading of P6, which is what the second layer below is for.
Second, and stronger: validation against Primavera P6 itself. On 2026-08-11 the 13 comparison cases below were built inside P6 Professional 23.12 by an automated import, scheduled with a single F9, and P6's computed dates and float were read back and compared. The first capture returned 6 of 13. The seven failures resolved into five named divergence families; each was fixed in both implementations against P6's pinned answers, with the fix history public in the repository. The matrix now stands at 13 of 13. The engine makes no P6 parity claim beyond the ground these cases cover. Re-capture is not automatic: it costs one import and one F9 in P6 by a human operator. The capture sheet the applier reads sits outside the public repository, so the matrix cannot be regenerated end to end from a clean clone. The committed import XER and the per-case comparison CSVs preserve P6's answers, so the capture stays inspectable. The honest reading is that these thirteen behaviours are now correct, not that the next thirteen would pass first time. The third layer tests exactly that.
Third: a blind check on schedules the engine was never fitted to. On 13 October 2026, twelve new synthetic schedules were generated from a public randomness-beacon round. The rules of the check were committed before that round was published, so nobody could know the schedules in advance. The schedules were published, then each was scheduled in P6 Professional 23.12.1 on its own, and engine v2.10.1 was scored against P6 once, with no engine change before or after. 195 of 206 unfinished activities match P6 on all seven fields compared: early and late start and finish to the minute, total and free float in hours, and the critical flag. Seven of the twelve schedules match on every field. The eleven that differ fall in four situations, listed below. The check is held out, not independent: CPP wrote the generator and the scorer and ran P6. What makes it blind is the beacon seed and the order of events, and every step is public in the held-out folder.
Known limitations are published, not buried. Since v2.10.0 the engine schedules P6's hours to the minute; where the hours pass cannot run, sub-day lags round with a fatal-in-strict-mode alert. The driving predecessor and the time-impact figure are still worked in whole days. Resource levelling is not modelled. Free-float parity carries one documented asymmetry noted below. Two cases that P6 cannot construct by design live in a separate engine-limitations folder and carry no P6 verdict.
Results
Every fixture, and its check count
The Skip column counts comparisons the harness does not perform because at least one port does not emit the field. The harness counts them: 0 fall on ff_signed_working_days and 0 on ff_signed, giving 0 in total across 0 of the 233 fixtures. All 0 are cases where NEITHER implementation emits the field, on completed activities, so there is nothing to verify and no port gap behind them. None is a case where this engine returns a computed value and the Python reference returns none: that class of skip numbered 58 until the has-successors branch was ported, and now numbers zero.
| ID | Fixture | Checks | Fail | Skip |
|---|---|---|---|---|
| F1 | A→B→C linear, no cal | 33 | 0 | 0 |
| F2 | A→B→C linear, MonFri | 33 | 0 | 0 |
| F3 | A→B→C + A→X (off-CP), MonFri | 42 | 0 | 0 |
| F4 | Mixed FS/SS/FF/SF + lags | 51 | 0 | 0 |
| F5 | MonFri + holidays | 24 | 0 | 0 |
| F6 | 7-day calendar (no weekends) | 24 | 0 | 0 |
| F6.5 | SF + FS mix | 33 | 0 | 0 |
| F7 | Diamond network | 51 | 0 | 0 |
| F8 | Numeric codes interleaved with alpha codes | 60 | 0 | 0 |
| F9 | FS-3 lead | 24 | 0 | 0 |
| F10 | Completed + uncompleted mix | 33 | 0 | 0 |
| F11 | MonFri + 7-day calendars mixed | 33 | 0 | 0 |
| F12 | early_start pin ahead of logic | 33 | 0 | 0 |
| F13 | SNET primary constraint | 24 | 0 | 0 |
| F14 | MS_Start + FNLT combo | 33 | 0 | 0 |
| F15 | ALAP consumes float | 42 | 0 | 0 |
| F16 | SNLT primary (forward ALERT + backward LF clamp) | 24 | 0 | 0 |
| F17 | FNET pushes EF forward (warn) | 15 | 0 | 0 |
| F18 | MS_Finish LF pin (forward warn + backward clamp) | 24 | 0 | 0 |
| F19 | Secondary constraint pair (SNET + FNLT window) | 24 | 0 | 0 |
| F20 | Out-of-sequence (completed B before A starts) | 24 | 0 | 0 |
| F21 | ALAP slide suppressed by actual_start | 42 | 0 | 0 |
| F22 | Calendar fallback (missing clndr_id triggers ALERT) | 24 | 0 | 0 |
| F23 | Cycle detection (both engines refuse) | 1 | 0 | 0 |
| F24 | Free-float parity DOCUMENTED GAP (no FF in Python ref) | 24 | 0 | 0 |
| F26 | Calendar fallback, 3 distinct missing clndr_ids | 33 | 0 | 0 |
| F27 | actual_start AFTER data_date pins ES (P6 forward-pass semantics) | 24 | 0 | 0 |
| F28 | ALAP primary + FNLT secondary compound | 42 | 0 | 0 |
| F29 | Mixed FF + SS predecessors converge on same successor | 33 | 0 | 0 |
| F30 | Negative lag FS-2 (no calendar, ordinal arithmetic) | 24 | 0 | 0 |
| F31 | Cycle in sub-network (A→B→C clean + D↔E cycle) | 1 | 0 | 0 |
| F32 | Far-future date arithmetic (2037-12-15 + 100d, post-Y2038) | 15 | 0 | 0 |
| F33 | MS_Start primary pins LS=ES, TF=0 (v2.9.12 T1.1) | 33 | 0 | 0 |
| F34 | MS_Start suppressed by actual_start (v2.9.12 T1.2) | 15 | 0 | 0 |
| F35 | unrecognized constraint token (v2.9.12 T1.6) | 15 | 0 | 0 |
| F36 | empty work_days falls back to MonFri (v2.9.12 T2.16) | 15 | 0 | 0 |
| F37 | CS_MANSTART alias (v2.9.12 T1.7) | 15 | 0 | 0 |
| F38 | CS_MANFINISH alias (v2.9.12 T1.7) | 15 | 0 | 0 |
| F43 | actual_finish without actual_start (v2.9.12 T4.25) | 15 | 0 | 0 |
| F44 | ALAP on secondary slot (v2.9.12 T4.26) | 24 | 0 | 0 |
| F45 | in-progress retained-logic LF=EF pin (F1-Bug1/F1-Bug2) | 33 | 0 | 0 |
| F46 | single in-progress activity retained-logic EF (F1-Bug2) | 15 | 0 | 0 |
| F47 | stored early_start NOT a SNET floor (F1-Bug5) | 15 | 0 | 0 |
| F48 | - out-of-sequence retained logic: remaining restarts behind pred (case 10) | 24 | 0 | 0 |
| F49 | - out-of-sequence progress_override: remaining continues from data date | 24 | 0 | 0 |
| F50 | special_workdays: a forced-ON Saturday and a forced-OFF Monday | 24 | 0 | 0 |
| F51 | pass-through: completed C carries unfinished P's date to X | 33 | 0 | 0 |
| F52 | progress_override ignores the pass-through (same topology as F51) | 33 | 0 | 0 |
| F53 | pass-through carries the lag into C; the lag out of C adds its unexpired part | 33 | 0 | 0 |
| F54 | pass-through survives a chain of two completed activities | 42 | 0 | 0 |
| F55 | SS_U: restart wins over actual_start+lag | 24 | 0 | 0 |
| F56 | SS_U: actual_start+lag wins when it exceeds the restart | 24 | 0 | 0 |
| F57 | PO_SNAP: progress_override restart snaps off a weekend data date | 15 | 0 | 0 |
| F58 | SSL: SS off a started predecessor whose restart is held past the data date | 33 | 0 | 0 |
| F59 | SSL: a used-up lag lays nothing; X starts on the held restart | 33 | 0 | 0 |
| F60 | SSL: SF off a started predecessor whose restart is held | 33 | 0 | 0 |
| F61 | SSL: an SS link off started work lays no lag into a completed activity | 42 | 0 | 0 |
| F62 | SSL: a future actual start uses up none of the lag | 24 | 0 | 0 |
| F63 | SSL: six-day predecessor, Mon-Fri successor, predecessor lag calendar | 33 | 0 | 0 |
| F64 | SSL: a started successor restarts at the held restart + unused lag | 33 | 0 | 0 |
| F65 | FA: FS+0 off an actual finish recorded weeks after the data date, beside an unfinished predecessor | 42 | 0 | 0 |
| F66 | FA: FS+2 off an actual finish after the data date is laid from the data date | 24 | 0 | 0 |
| F67 | FA: SS+3 off an actual start after the data date | 24 | 0 | 0 |
| F68 | FA: FF+2 off an actual finish after the data date | 24 | 0 | 0 |
| F69 | FA: the unexpired lag rides on a carried date | 33 | 0 | 0 |
| F70 | FA: the backward pass takes the unexpired lag off the carried bound | 42 | 0 | 0 |
| F71 | FA: a started successor restarts at the data date plus the unexpired lag | 24 | 0 | 0 |
| F72 | FA: progress override lays the lag from the data date too | 24 | 0 | 0 |
| F73 | FA: without a data date the actual dates still drive | 24 | 0 | 0 |
| F74 | FA: six-day predecessor, Mon-Fri successor, predecessor lag calendar | 24 | 0 | 0 |
| F75 | FA: a completed-to-completed link carries its unexpired lag | 33 | 0 | 0 |
| F76 | SSL measured: SS under lag from Actual Start is laid from the data date | 33 | 0 | 0 |
| F77 | SSL measured: under Actual Start the successor can start before the restart | 33 | 0 | 0 |
| F78 | SSL measured: a used-up lag under Actual Start starts on the data date (flag N) | 33 | 0 | 0 |
| F79 | SSL measured: Actual Start, six-day predecessor, Mon-Fri successor | 33 | 0 | 0 |
| F80 | SSL measured: under Actual Start a started successor restarts at the data date + unused lag | 33 | 0 | 0 |
| F81 | SSL measured: SF ignores lag from Actual Start | 33 | 0 | 0 |
| F82 | SSL measured: no lag from started work into a completed activity; float through it | 51 | 0 | 0 |
| F83 | SSL measured: into a completed activity under Actual Start the data date is carried | 51 | 0 | 0 |
| F84 | SSL measured: SF into a completed activity carries the restart under Actual Start | 42 | 0 | 0 |
| F85 | SSL measured: other links into completed work keep their lag | 96 | 0 | 0 |
| F86 | SSL measured: an unknown lag-from option alerts and keeps Early Start | 33 | 0 | 0 |
| F87 | MFB: an earlier Must Finish By seeds negative float | 42 | 0 | 0 |
| F88 | MFB: a later Must Finish By seeds positive float | 42 | 0 | 0 |
| F89 | MFB: a Must Finish By inside the working day | 42 | 0 | 0 |
| F90 | MFB: a Must Finish By on a non-working day | 42 | 0 | 0 |
| F91 | MFB: a bare-date Must Finish By | 42 | 0 | 0 |
| F92 | MFB: the Must Finish By on each activity's own calendar | 33 | 0 | 0 |
| F93 | MFB: an ordinal (calendar-less) network | 24 | 0 | 0 |
| F94 | MFB: an unparseable Must Finish By | 42 | 0 | 0 |
| F95 | MFB: a finish constraint beside the Must Finish By | 42 | 0 | 0 |
| F96 | RES: a completed activity resumed after the data date holds its successors | 42 | 0 | 0 |
| F97 | RES: a suspended activity restarts on its resume date | 24 | 0 | 0 |
| F98 | RES: a resume date at or before the data date | 24 | 0 | 0 |
| F99 | RES: progress override does not apply a resume date | 33 | 0 | 0 |
| F100 | CC: completed to completed, with and without a resume date | 51 | 0 | 0 |
| F101 | FF: free float to a completed successor's stamp | 33 | 0 | 0 |
| F102 | MFB + RES + CC together | 60 | 0 | 0 |
| F103 | RES: a resume date without a suspend date is not applied | 42 | 0 | 0 |
| F104 | MFB under "opened projects": the measured shape at a midnight data date | 105 | 0 | 0 |
| F105 | MFB under "opened projects": the measured shape at the 17:00 close | 105 | 0 | 0 |
| F106 | XF: with "Use Expected Finish Dates" on, an expected finish re-sizes the remaining work (stretch, shrink, logic, weekend, FF) | 159 | 0 | 0 |
| F107 | XF: the same network with the expected-finish option off | 159 | 0 | 0 |
| F108 | UW: finish constraints on work already under way | 105 | 0 | 0 |
| F109 | XF: an expected finish behind FF logic, retained logic | 159 | 0 | 0 |
| F110 | XF: an expected finish behind FF logic, progress override | 159 | 0 | 0 |
| F111 | XA: an expected finish that leaves no working time zeroes only unassigned work (data date Wed 17:00) | 330 | 0 | 0 |
| F112 | XA: the 704 h activity on a seven-day calendar keeps its remaining work | 42 | 0 | 0 |
| F113 | OW: start constraints on a Saturday, a holiday and after the close | 114 | 0 | 0 |
| F114 | OW: finish constraints on a Sunday (zero duration and two days) | 51 | 0 | 0 |
| F115 | AL: ALAP by free float (FS, a chain, SS, no free float, an open end) | 177 | 0 | 0 |
| F116 | FM: a finish milestone held at Friday 17:00 drives seven-day work from Saturday | 78 | 0 | 0 |
| F117 | SR: start float of work under way, start float, retained logic | 69 | 0 | 0 |
| F118 | SR: start float of work under way, smallest float, progress override | 69 | 0 | 0 |
| F119 | EX: external early start and external late finish, applied | 204 | 0 | 0 |
| F120 | EX: the same with relationships to other projects ignored | 204 | 0 | 0 |
| F121 | MD: milestone instants at a Monday opening | 321 | 0 | 0 |
| F122 | MD: milestone instants on the parity probe shapes | 186 | 0 | 0 |
| F123 | MD: a Friday-close data date and a close off the milestone's own calendar | 42 | 0 | 0 |
| F124 | WD: zero-length tasks close late, and hand the close back | 141 | 0 | 0 |
| F125 | WD: progress override honours the links into a started activity's finish | 105 | 0 | 0 |
| F126 | HR: a half-day lag and a half-day activity, to the minute | 37 | 0 | 0 |
| F127 | HR: work a pipeline inserted (no hours) or re-sized (days moved) is sized from its days | 37 | 0 | 0 |
| F128 | HR: SS lag off suspended work, SF off started work under "lag from Actual Start" | 57 | 0 | 0 |
| F129 | HR: an SF requirement after lunch, an FF requirement off working time | 57 | 0 | 0 |
| F130 | HR: ALAP by free float, a Start On off working time, a timed constraint | 77 | 0 | 0 |
| F131 | HR: progress override, completed work after the data date, an exception day with hours | 67 | 0 | 0 |
| F132 | RD: assignments on their resources' calendars; a lag delays its assignment; a non-driving one drives nothing | 47 | 0 | 0 |
| F133 | RD: the start takes the activity calendar's opening; the late side its close; a start-no-later-than caps it | 57 | 0 | 0 |
| F134 | RQ: FF and SF requirements on resource dependent work, on an opening and inside working time | 67 | 0 | 0 |
| F135 | XR / XZ: an expected finish re-sizes each assignment; work it zeroes in this pass stays at its start | 47 | 0 | 0 |
| F136 | PF: the printed float is the hours float in working days; critical is total float <= 0 in hours | 67 | 0 | 0 |
| F137 | PF: under FT_Min both floats follow the hours pass, on a seven-day calendar beside a five-day one | 57 | 0 | 0 |
| F138 | float on work no calendar reaches is counted on the 7-day days it was scheduled on | 33 | 0 | 0 |
| F139 | a completed activity finished on a later day than the data date: the alert in both engines, and every free-float field | 33 | 0 | 0 |
| F140 | a constraint handed back normalized (date + time_minutes, as getTasks() carries it) keeps its time | 57 | 0 | 0 |
| F141 | SC: Start On or Before, Start On and Mandatory Start on work under way drop from the late side, whole days | 78 | 0 | 0 |
| F142 | SC: the same constraints in hours; a Start On or Before or Mandatory Start takes the other constraint with it | 87 | 0 | 0 |
| F143 | AS: As Late As Possible under way, past its late finish and as an open end, whole days | 87 | 0 | 0 |
| F144 | AS: the same in hours | 97 | 0 | 0 |
| F145 | AS: under progress override an SS link out of started ALAP work holds nothing back (hours) | 97 | 0 | 0 |
| F146 | FL: free float across a lag on the successor’s calendar, seven-day work into five-day work | 97 | 0 | 0 |
| F147 | FL: free float across a lag on the 24-hour calendar | 97 | 0 | 0 |
| F148 | MD: a Mandatory Start or Finish before the data date on work not started starts at the data date, whole days | 96 | 0 | 0 |
| F149 | MD: the same in hours | 107 | 0 | 0 |
| F150 | MD: the same in hours, under progress override | 107 | 0 | 0 |
| F151 | SR: start-to-start free float out of work under way runs from the restart, lag from Actual Start, whole days | 150 | 0 | 0 |
| F152 | SR: the same in hours | 167 | 0 | 0 |
| F153 | SO: under progress override an SS or SF link out of work under way holds no free float, whole days | 150 | 0 | 0 |
| F154 | SO: the same in hours, lag from Actual Start | 167 | 0 | 0 |
| F155 | SO: the same in hours, lag from Early Start | 167 | 0 | 0 |
| F156 | LC: a lead landing on a close keeps it as the late start, and its tie with the late finish, in hours | 227 | 0 | 0 |
| F157 | MC: a milestone applies no constraint of its other end, whole days | 195 | 0 | 0 |
| F158 | MC: the same in hours | 217 | 0 | 0 |
| F159 | PD: under progress override an SS link out of work under way is laid from the data date, whole days | 51 | 0 | 0 |
| F160 | PD: the same in hours, lag from Early Start, the data date at the end of the day | 117 | 0 | 0 |
| F161 | PD: the same on a 24-hour lag calendar | 117 | 0 | 0 |
| F162 | XM / LC: an expected finish on milestones, and a lead tied with a finish-to-finish successor, in hours | 167 | 0 | 0 |
| F163 | FL: a lag handed on in days, under the successor lag calendar, from a 10-hour-day predecessor onto 6-hour-day successors, in hours | 37 | 0 | 0 |
| F164 | AP: As Late As Possible work and an FS or SS link into a successor under way, under progress override, in hours | 137 | 0 | 0 |
| F165 | AP: the same, whole days | 123 | 0 | 0 |
| F166 | MP: a Mandatory Start or Finish against an earlier link bound, a weekend tie, both pins, Start On or Before controls, in hours | 217 | 0 | 0 |
| F167 | EP: a schedule dated 2013 with work under way, completed work and a constraint, in whole days | 69 | 0 | 0 |
| F168 | EP: the same, in hours | 77 | 0 | 0 |
| F169 | AU: As Late As Possible work under way over start-to-start and start-to-finish lags, in hours | 167 | 0 | 0 |
| F170 | AU: the same, whole days | 150 | 0 | 0 |
| F171 | PS: SS lag from the Actual Start: a start-to-start link out of completed work carries no date, in hours | 177 | 0 | 0 |
| F172 | PS: the same, whole days | 159 | 0 | 0 |
| F173 | RO: under progress override a resume date after the data date holds work under way, in hours | 127 | 0 | 0 |
| F174 | RO: the same, whole days | 114 | 0 | 0 |
| F175 | SU: an SS / SF lag off a suspended predecessor, the suspension left out forward and counted backward, in hours | 117 | 0 | 0 |
| F176 | SU: the same, whole days | 105 | 0 | 0 |
| F177 | ZP: resource dependent work whose start a finish requirement sets, an assignment with no work after it keeping its own time, in hours | 127 | 0 | 0 |
| F178 | RL: resource dependent work with an assignment that has no work and no bound taken keeps its late finish where its work ends, in hours | 37 | 0 | 0 |
| F179 | XL: no expected finish on As Late As Possible work, under way or not; it still applies with no constraint and with another one, in hours | 137 | 0 | 0 |
| F180 | XL: the same, in whole days | 123 | 0 | 0 |
| F181 | OC: open-ended work takes no later finish than its own early finish, a Must Finish By still capping it, in hours | 147 | 0 | 0 |
| F182 | OC: the same network under progress override and no Must Finish By, in whole days | 132 | 0 | 0 |
| F183 | OC: completed work with no successor is an open end under retained logic; a level of effort or WBS summary successor makes work not open-ended, in hours | 137 | 0 | 0 |
| F184 | OC: the same network, in whole days | 123 | 0 | 0 |
| F185 | XC: an expected finish drops the early side of a finish constraint on work not yet started, in hours | 147 | 0 | 0 |
| F186 | XC: the same, in whole days | 132 | 0 | 0 |
| F187 | The four relationship checks both engines raise: a self-loop, an unknown type, a lag that is not a number, a link to no activity | 33 | 0 | 0 |
| F188 | XP, MR and XC on finish milestones: a Mandatory Finish under an expected finish caps the late finish, and resource dependent work takes a mandatory pin, in hours | 297 | 0 | 0 |
| F189 | XP, MR and XC: the same, in whole days, where a milestone with an expected finish keeps zero duration | 267 | 0 | 0 |
| F190 | XP and MR: the same network with "Use Expected Finish Dates" off, where every mandatory date pins, in hours | 297 | 0 | 0 |
| F191 | XP and MR: the same with the option off, in whole days | 267 | 0 | 0 |
| F192 | PC: a mandatory date beside a second constraint: only the primary pins and the second caps, in whole days | 258 | 0 | 0 |
| F193 | PC: the same, in hours | 287 | 0 | 0 |
| F194 | Input checks both engines raise: a null activity, a missing code, a padded code, a duplicate code, a control character in a name | 51 | 0 | 0 |
| F195 | Input checks: an empty network | 6 | 0 | 0 |
| F196 | Input checks: an invalid constraint date, an invalid activity date, inverted actuals, a remaining duration longer than the duration | 69 | 0 | 0 |
| F197 | SL, MG, MX and FZ: a mandatory date in the second slot is a floor, a Mandatory Start ignores finish-to-finish logic and external dates, and As Late As Possible work holds no free float, in hours | 367 | 0 | 0 |
| F198 | SL, MG, MX and FZ: the same, in whole days | 330 | 0 | 0 |
| F199 | XO, XE and ZB: an expected finish with a finish-to-finish requirement off working time, resource dependent work under an expected finish, and a lagged assignment with no work under a start-to-start bound, in hours | 147 | 0 | 0 |
| F200 | AV: As Late As Possible resource dependent work under way, its slid restart off its calendar, in hours | 57 | 0 | 0 |
| F201 | FP: F197 under "Calculate multiple float paths", in hours | 367 | 0 | 0 |
| F202 | FP: F198 under "Calculate multiple float paths", in whole days | 330 | 0 | 0 |
| F203 | SL: a primary Mandatory Start beside a later or earlier second constraint, in hours | 207 | 0 | 0 |
| F204 | SL: the same, in whole days | 186 | 0 | 0 |
| F205 | QS: work a finish-to-finish requirement places starts where its resource first works after the activity calendar opens, in hours | 117 | 0 | 0 |
| F206 | ZL: a lagged assignment with no work whose lag lands off the activity calendar, in hours | 117 | 0 | 0 |
| F207 | XW: an expected finish sizes resource dependent work once, from its first placement, in hours | 117 | 0 | 0 |
| F208 | ZR: an assignment with no duration and no lag runs back from the late finish under a start-to-start bound, in hours | 237 | 0 | 0 |
| F209 | ZW: an assignment with no units and no units per hour keeps the hours between its own dates, in hours | 217 | 0 | 0 |
| F210 | ZF and BM: a lagged assignment with no work under a start-to-start bound that another assignment can outlast, in hours | 267 | 0 | 0 |
| F211 | AG: As Late As Possible resource dependent work with no working time to gain does not slide, in hours | 177 | 0 | 0 |
| F212 | FK: As Late As Possible work with the float paths ending at an activity it does not lead into holds no free float, in hours | 367 | 0 | 0 |
| F213 | FK: the same, in whole days | 330 | 0 | 0 |
| F214 | FK: the float paths ending at an activity the work leads into, which keeps its free float, in hours | 367 | 0 | 0 |
| F215 | FK: an end that is not an activity of the network changes nothing, in whole days | 330 | 0 | 0 |
| F216 | MZ: a finish milestone at the 24:00 close of a day before one not worked, in hours | 57 | 0 | 0 |
| F217 | UM: a Finish On or Before and a Mandatory Finish on work under way both leave the late side, in hours | 147 | 0 | 0 |
| F218 | UM: the same, in whole days | 132 | 0 | 0 |
| F219 | ZU: the lag of an assignment with no units on work under way counts from the actual start, in hours | 117 | 0 | 0 |
| F220 | As Late As Possible resource dependent work under a start-to-start or start-to-finish bound, in hours | 127 | 0 | 0 |
| F221 | The same under "Start Float": the start float of work so placed, in hours | 127 | 0 | 0 |
| F222 | ZQ: an assignment with no work and a lag bounds the start of work placed back from a finish requirement, in hours | 97 | 0 | 0 |
| F223 | As Late As Possible resource dependent work that would finish off the activity calendar, in hours | 107 | 0 | 0 |
| F224 | AW: the shapes of P6 probe round 16, in hours | 107 | 0 | 0 |
| F225 | AW: As Late As Possible resource dependent work placed back twice from a start bound, in hours | 287 | 0 | 0 |
| F226 | AT: F225 under "Start Float" and progress override, start float from the bound, in hours | 287 | 0 | 0 |
| F227 | AW: F226 with "Calculate multiple float paths", start float from the start, in hours | 287 | 0 | 0 |
| F228 | AZ: As Late As Possible resource dependent work with no work left sits at its resources' next opening, in hours | 107 | 0 | 0 |
| F229 | MW and LR: finish floors compared by start, and the late pin placed on the resources first, in hours | 107 | 0 | 0 |
| F230 | FT: FT_Start with the float paths ending at the finish milestone, in hours | 77 | 0 | 0 |
| F231 | FT: the same with the paths ending at a branch the resource dependent work does not lead into, in hours | 77 | 0 | 0 |
| F232 | FT: F230 under "Smallest", in hours | 77 | 0 | 0 |
| F233 | FT: F230 under FT_SS, the code P6's dialog writes for "Start Float", where RT is set aside, in hours | 77 | 0 | 0 |
| F234 | FT: FT_SS under retained logic, with no end and no multiple float paths, in hours | 77 | 0 | 0 |
| F235 | FT: F230 written FT_Total with no end, read as FT_Start, in hours | 77 | 0 | 0 |
| F236 | AZ and MO: work with no work left kept at its resource's opening, and a Mandatory Start that pins the span of its work, in hours | 157 | 0 | 0 |
| F237 | MO: F236 under "Start Float" with lags on 24 hours, in hours | 157 | 0 | 0 |
Fixture identifiers are not contiguous. F6.5 was inserted between F6 and F7, and F25 and F39 through F42 are absent because fixtures were consolidated across earlier audit rounds. The set is 233 fixtures as listed. Cycle-detection fixtures F23 and F31 carry a single check each, because the only correct behaviour is that both implementations refuse the input.
Detail
Run manifestVersions, the pinned reference hash, and how to reproduce this page
| Item | Value |
|---|---|
| Engine version | cpm-engine v2.10.17 |
| Run date | 2026-11-09 |
| Node.js | v22.19.0 |
| Python | 3.12.10 |
| Python reference | python_reference/cpm.py, 331779 bytes |
| Reference SHA-256 | 12a8f55a2f94f3ae367e7b045a89533178188ece3c844679f254b4b2846b1b62 |
| Licence | MIT |
| Repository | github.com/danafitkowski/cpp-cpm-engine |
The Python reference is pinned by SHA-256 and the hash is printed at the start of every run, so an external auditor can confirm the reference has not drifted between runs. To reproduce:
git clone https://github.com/danafitkowski/cpp-cpm-engine cd cpp-cpm-engine git checkout v2.10.17 npm install npm run test:all
The tag is pinned deliberately. This page records a run performed on 9 November 2026 at engine v2.10.17, and the hashes and dates below are that run's. Checking out the tag is what makes them reproducible; v2.10.17 is the current release, and the 1,524 unit tests pass in the same run. The agreement figure moved from the 931 of 995 recorded at v2.9.41 when v2.9.42 corrected constraint pairing and restored SS/SF late-finish conversion; it has held at 1009 of 1015 through v2.9.43 and v2.9.44. v2.9.44 changed the arithmetic where a relationship crosses calendars: a successor now starts from its predecessor's finish instant, placed on the successor's own calendar, and the backward pass mirrors it. Every fixture except the mixed-calendar F11 computed the same values before and after that change, and on F11 the two implementations agree on the new reading. It grew to 1167 of 1183 when v2.9.46 added seven fixtures for the retained-logic pass-through, and to 1957 of 2011 when v2.9.47 added twenty-nine for the unexpired part of a lag off started and completed work; the fixtures that existed before each change agree in both implementations after it, F53 moving one working day to the measured value in both. It grew again, to 2465 of 2539, when v2.9.49 added seventeen (F87 to F103) for the Must Finish By, suspend and resume dates and links between completed activities, to 2623 of 2705 when v2.9.50 added two (F104 and F105) for the Must Finish By under "opened projects", measured in P6, to 3202 of 3288 when v2.9.52 added five (F106 to F110) for P6's "Use Expected Finish Dates" and for finish constraints on work already under way, both measured in P6, to 3482 of 3580 when v2.9.53 added two (F111 and F112) for an expected finish that leaves no working time, where P6 keeps the remaining work of an activity with a resource assignment, also measured in P6, and to 3814 of 3912 when v2.9.54 added four (F113 to F116) for constraints dated on time the calendar does not work, As Late As Possible work that slides by its free float, and a finish milestone held at a Friday close, all measured in P6, and to 3924 of 4022 when v2.9.55 added two (F117 and F118), the first to hand both implementations a total float method, for the start float of work under way, which P6 measures from the restart rather than the actual start, also measured in P6, and to 4244 of 4342 when v2.9.57 added two (F119 and F120) for an activity's external early start and external late finish, applied and ignored, also measured in P6, and to 4675 of 4773 when v2.9.58 added three (F121 to F123) for the dates a milestone prints, measured on P6's own output, and the dates check began carrying the printed finish dates, and to 4869 of 4967 when v2.9.59 added two (F124 and F125) for zero-length tasks closing late and progress override's links into a started activity's finish, measured on P6's own output, and to 5133 of 5233 when v2.10.0 added six (F126 to F131) that hand both implementations P6's hours and compare the hours pass as well, the engine now scheduling in hours and minutes, measured on P6's own output, and to 6994 of 6994 when v2.10.1 added nine (F132 to F140) for resource dependent work, the float and critical set P6 prints, float on work no calendar reaches, a future actual finish and constraints handed back normalized, every activity's start and finish float joined the comparison, and the harness stopped skipping anything; it reached 7634 of 7634 when v2.10.2 added seven (F141 to F147) for start constraints on work under way, As Late As Possible and free float across a lag, and 8745 of 8745 when v2.10.3 added eight (F148 to F155) for a mandatory date before the data date, start-to-start free float out of work under way, and start-to-start and start-to-finish links out of work under way under progress override, and 9836 of 9836 when v2.10.4 added seven (F156 to F162) for start-to-start links out of work under way under progress override laid from the data date, a constraint of a milestone's other end, a lead that lands on a close, and an expected finish on a milestone, and 9873 of 9873 when v2.10.5 added one (F163) for a lag handed on in days under the successor lag calendar, and 10350 of 10350 when v2.10.6 added three (F164 to F166) for As Late As Possible work past a successor under way and a mandatory date against an earlier link bound, and 11149 of 11149 when v2.10.7 added six (F167 to F172) for a schedule dated before 2020, As Late As Possible work under way over a start-to-start or start-to-finish lag, and a start-to-start link out of completed work under "Actual Start", and 11390 of 11390 when v2.10.8 added two (F173 and F174) for a resume date after the data date under progress override, and 11612 of 11612 when v2.10.9 added two (F175 and F176) for a lag off a suspended predecessor, and 11776 of 11776 when v2.10.10 added two (F177 and F178) for the finish of resource dependent work under a finish requirement and for RL in the Python engine, and 12887 of 12887 when v2.10.11 added nine (F179 to F187) for its three rules and the Python reference's relationship checks, and 17926 of 17926 when v2.10.12 added twenty-four (F188 to F211) for its twenty-one rules and the Python reference's input checks, and 22189 of 22189 when v2.10.13 added twenty-six (F212 to F237) for its twelve rules. v2.10.14 added none: what it changes, the driver the engine records for work under way, is not a compared field. v2.10.15 added none: what it changes, how the XER parser reads a blank lag, is not on the harness's path. v2.10.16 added none: what it changes, the driver the engine records, is not a compared field. v2.10.17 added none: it changes no code in this engine. The run prints the reference path, byte count and SHA-256 before the first fixture, then one line per field check. The final block prints the fixture and check totals shown on this page.
What is compared on each fixtureThe enumerated field set, with the number of checks each contributes
Comparison is field by field rather than on a single summary value. A fixture passes only if every enumerated field matches between the two implementations.
| Field | Checks | What it is |
|---|---|---|
| node <id> | 20721 | Per-activity values: early start, early finish, late start, late finish, total float, the rendered dates, total float in working days, free float, and free float in working days; where P6's hours are handed on, also the instants to the minute, the float in hours and the day-pass dates |
| project_finish_num | 231 | Project finish as an ordinal day number |
| project_finish | 231 | Project finish as a rendered date |
| critical_codes | 231 | The set of activity codes on the critical path |
| topo_order | 231 | Topological sort order |
| alert_count | 231 | Number of alerts raised |
| alert_severity_counts | 231 | Alert counts broken down by severity |
| hours | 80 | The hours pass, on the fixtures that hand both implementations P6's hours: whether it ran, the project finish instant and the activities sized from their days (the per-activity instants and float in hours are counted under node <id>) |
| threw (both engines) | 2 | Both implementations refuse the input and raise, on cycle-detection fixtures |
Per-activity checks dominate the count because every activity in every fixture contributes its early and late dates, total float, free float, the rendered date strings, and both float values converted to working days on that activity's own calendar.
Documented gaps and disclosed limitationsThree items, stated plainly, each with the fixture or case that exercises it
1. Free-float parity is a documented gap
Fixture F24 was labelled a documented gap in the suite itself when the Python reference did not compute free float. That gap closed when the free-float port landed: ff and ff_working_days are cross-validated on every fixture, and the signed variants on every activity: since v2.10.1 both engines emit them on completed work too, so nothing remains uncompared.
2. Part-day work without the hours pass, and two whole-day results
P6 stores durations and lags in hours. Since v2.10.0 the engine schedules those hours to
the minute when they are handed on, as the XER parser does. Where they are not, or there is no
data date or calendar, the whole-day pass runs alone: a sub-day lag raises a
SUB_DAY_LAG_ROUNDED alert and rounds, and in forensic strict mode that alert is
fatal, so the engine refuses to produce a result rather than quietly rounding. The case is
validation/engine-limitations/cases/01-fractional-lag-engine-rounds/. Two results
are still worked in whole days even with the hours pass: the driving predecessor, with the
longest path traced through it, and the impact figure of a time impact analysis. On part-day
work those can name the wrong driver or round a few hours of delay up to a day. Since v2.10.16
each is checked against the hours pass and withheld, with an alert, where the two disagree;
nothing is worked out in its place, so on part-day work the result can be missing. The check
does not cover a driver held by the data date or a constraint, and it does not catch every
wrong driver: on the 380 exports compared with P6's own longest-path flags, 130 drivers still
disagree with P6 and are not withheld.
3. Two cases are known to diverge from P6 by construction
Fractional lag and dangling relationships test inputs P6 itself cannot produce. Rather than
leave them in the P6 comparison matrix where they would look like failures or be silently
dropped, they were moved to validation/engine-limitations/cases/ and will never
carry a P6 verdict. A dangling relationship, meaning one that references an activity not
present in the file, raises an alert and the relationship is dropped; in forensic strict mode
it is fatal.
P6-native comparison matrix: 13/13 validatedCaptured from Primavera P6 Professional 23.12 on 2026-08-11; first capture 6/13, five divergence families fixed against the pinned answers, now 13/13
The engine's answers were published before P6 was asked the same questions, and the capture itself was blind: an automated harness imported the 13 mini-projects into P6 Professional 23.12, a human pressed F9 once, and P6's stored answers were read back from the database. The first capture scored 6 of 13. The seven failures were diagnosed into five divergence families (working-day float units, open-end late-date seeding, mandatory-finish semantics, retained logic on out-of-sequence progress, and free-float conventions), fixed in both engine implementations against P6's pinned numbers, and the matrix re-verified at 13 of 13. Every fix is a public commit citing the capture.
| # | Case | Engine project finish | Alerts | P6 verdict | What it tests |
|---|---|---|---|---|---|
| 01 | 01-fs-chain | 2026-01-19 | 0 | PASS | Baseline FS chain. Should match P6 exactly. |
| 02 | 02-ss-with-lag | 2026-01-19 | 0 | PASS | SS+5 with parallel-finish behaviour |
| 03 | 03-ff-with-lag | 2026-01-15 | 0 | PASS | FF+3 forces B finish behind A finish |
| 04 | 04-sf-edge-case | 2026-01-12 | 0 | PASS | Least-common relationship type; SF behaviour varies with the P6 progress-override setting |
| 05 | 05-negative-float | 2026-01-21 | 1 | PASS | FNLT constraint produces negative total float |
| 06 | 06-multiple-calendars | 2026-01-19 | 0 | PASS | Activity-specific calendars, 5-day against 6-day |
| 07 | 07-ontario-holidays | 2026-05-13 | 0 | PASS | Long activity across Ontario statutory holidays |
| 08 | 08-in-progress-retained-logic | 2026-01-28 | 0 | PASS | Predecessor in progress; successor anchored to projected early finish |
| 09 | 09-completed-successor | 2026-01-12 | 2 | PASS | Backward-pass skip; no pull-back through a historical finish |
| 10 | 10-out-of-sequence-progress | 2026-01-29 | 1 | PASS | Out-of-sequence alert path |
| 11 | 11-mandatory-start-finish | 2026-01-30 | 2 | PASS | Mandatory Start and Mandatory Finish hard pins |
| 12 | 12-snet-fnlt | 2026-02-03 | 1 | PASS | Start-No-Earlier-Than and Finish-No-Later-Than, the two most common P6 constraints |
| 13 | 13-alap | 2026-01-22 | 0 | PASS | As-Late-As-Possible secondary constraint |
Alert counts include informational alerts. The remaining alerts are by design: the completed-successor backward-pass skip on case 09, out-of-sequence progress on case 10, and constraint-application alerts on cases 05, 11 and 12.
Two cases formerly numbered 14 and 15 are excluded by construction and live under
validation/engine-limitations/. See the gaps drawer above.
Held-out P6 check H1: 195 of 206 activities on every fieldTwelve beacon-seeded schedules, published before P6 saw them, scored once on 13 October 2026
The order of events is what makes this check blind. The rules, the generator, the scorer and the P6 read-back were committed first, naming drand round 6549295. The twelve schedules were generated from that round's randomness after it was published and pushed before P6 saw any of them. Each was then imported into P6 Professional 23.12.1 and scheduled on its own, P6's answers were read back from its database read-only, and engine v2.10.1 was scored against them once. Nothing was changed between the freeze and the score.
| Schedule | Unfinished activities | Match on all seven fields | Result |
|---|---|---|---|
| H1-01 | 29 | 29 | every field |
| H1-02 | 21 | 18 | 3 differ |
| H1-03 | 14 | 13 | 1 differ |
| H1-04 | 23 | 23 | every field |
| H1-05 | 6 | 6 | every field |
| H1-06 | 6 | 6 | every field |
| H1-07 | 29 | 29 | every field |
| H1-08 | 22 | 22 | every field |
| H1-09 | 15 | 15 | every field |
| H1-10 | 7 | 5 | 2 differ |
| H1-11 | 11 | 10 | 1 differ |
| H1-12 | 23 | 19 | 4 differ |
| Total | 206 | 195 |
The eleven activities that differ fall in four situations, each published field by field:
- a Start On or Before constraint on work already started (H1-02, three activities);
- As Late As Possible on work already started (H1-03, one activity);
- an expected finish earlier than the data date on started work with a Start On constraint (H1-12, four activities);
- free float measured across a lag on another calendar, with every date the same (H1-10 and H1-11, three activities).
The engine is not changed against this set. A later release that changes any of these is scored on a new held-out set, seeded the same way, and this result stays as published. The full record is in the repository's H1 result.
Held-out P6 check H2: 169 of 171 activities on every field, 174 of 176 with the read-back correctedThe engine changed to the rules H1 led to, then scored once on twelve new beacon-seeded schedules, 13 October 2026
The differences H1 found came down to three rules in P6: start constraints on work under way, As Late As Possible under way and past its late finish, and free float across a lag on another calendar. P6 probes measured those rules, and engine v2.10.2 was changed to reproduce them. The probes are therefore fitted. H2 is the held-out test of that change: the v2.10.2 bytes and the rules of the check were committed first, naming drand round 6549541, and the twelve schedules were generated from that round after it was published and pushed before P6 saw them. P6 Professional 23.12.1 scheduled each on its own, and v2.10.2 was scored once.
169 of 171 unfinished activities match P6 on all seven fields, on the eleven schedules the read-back kept. It left out H2-09 on a false alarm: P6 stamps its schedule run in milliseconds and writes the rows it changes in whole seconds, and the check read those rows as edited after the run. Read back with that corrected, all twelve schedules score 174 of 176. Both results are published; the table shows all twelve, with H2-09 read back that way.
| Schedule | Unfinished activities | Match on all seven fields | Result |
|---|---|---|---|
| H2-01 | 8 | 8 | every field |
| H2-02 | 18 | 18 | every field |
| H2-03 | 15 | 14 | 1 differ |
| H2-04 | 7 | 7 | every field |
| H2-05 | 19 | 19 | every field |
| H2-06 | 7 | 6 | 1 differ |
| H2-07 | 29 | 29 | every field |
| H2-08 | 14 | 14 | every field |
| H2-09 | 5 | 5 | every field (read-back corrected) |
| H2-10 | 26 | 26 | every field |
| H2-11 | 11 | 11 | every field |
| H2-12 | 17 | 17 | every field |
| Total | 176 | 174 |
H2's random draw tested only the free-float rule, and the engine moved exactly two values in the whole set, both onto P6's. No schedule had started work under Start On or Before, Start On or Mandatory Start, or As Late As Possible work the new rule moves, so those two rules still rest on the fitted probes. The two activities that differ were already different in v2.10.1:
- a Mandatory Start dated before the data date on work not started (H2-06): P6 starts the work at the data date and keeps the mandatory date on the late side;
- free float to a start-to-start successor out of work under way, with lag counted from the actual start (H2-03): P6 measures it from the restart, one hour less than the engine.
The engine is not changed against H2. A later release that changes either situation is scored on a new held-out set. The full record is in the repository's H2 result.
Held-out P6 check H3: 244 of 253 activities on every fieldThe engine changed to the rules H2 led to, then scored once on twelve new beacon-seeded schedules, 13 October 2026
H2's two differences, a Mandatory Start dated before the data date on work not started and free float to a start-to-start successor out of work under way, were measured on six P6 probe projects, which also showed a third rule, for start-to-start and start-to-finish links out of work under way under progress override. Engine v2.10.3 was changed to reproduce all three, so the probes are fitted. H3 is the held-out test of that change: the v2.10.3 bytes and the rules of the check were committed first, naming drand round 6549889, and the twelve schedules were generated from that round after it was published and pushed before P6 saw them. P6 Professional 23.12.1 scheduled each on its own, and v2.10.3 was scored once.
244 of 253 unfinished activities match P6 on all seven fields, and nine of the twelve schedules match on every field. Run on the same schedules after the score, as a diagnosis, v2.10.2 matches 226 of 253.
| Schedule | Unfinished activities | Match on all seven fields | Result |
|---|---|---|---|
| H3-01 | 17 | 17 | every field |
| H3-02 | 32 | 32 | every field |
| H3-03 | 27 | 27 | every field |
| H3-04 | 29 | 26 | 3 differ |
| H3-05 | 14 | 14 | every field |
| H3-06 | 23 | 23 | every field |
| H3-07 | 13 | 13 | every field |
| H3-08 | 23 | 23 | every field |
| H3-09 | 15 | 15 | every field |
| H3-10 | 15 | 15 | every field |
| H3-11 | 22 | 17 | 5 differ |
| H3-12 | 23 | 22 | 1 differ |
| Total | 253 | 244 |
Against v2.10.2 the engine moved 71 values on 18 activities, every one onto P6's and none away. H3 confirmed the mandatory-date rule on one activity and the progress-override rule on two schedules. It gave the free-float rule nothing to move, so that rule still rests on the fitted probes. The nine activities that differ were already different in v2.10.2, and they come from three situations:
- under progress override with lag counted from Early Start, a start-to-start link out of work under way where the data date falls at the end of the predecessor's working day (H3-04): P6 starts the successor at the data date, the engine at the predecessor's restart. This falls inside the progress-override rule and counts against it;
- a Start On or Before on a finish milestone (H3-11): P6 keeps the constraint on the activity but does not apply it;
- a late start set by a start-to-start successor with a negative lag, landing exactly at a lunch break (H3-11, H3-12): P6 prints the end of the morning and the engine the start of the afternoon, the same working time on the activity's calendar but half an hour on a predecessor that works around the clock.
The engine is not changed against H3. A later release that changes any of these situations is scored on a new held-out set. The full record is in the repository's H3 result.
Held-out P6 check H4: 233 of 237 activities on every fieldThe engine changed to the rules H3 led to, then scored once on twelve new beacon-seeded schedules, 14 October 2026
H3's three differences were measured on eighteen P6 probe projects, and checking the changed engine against every project P6 had scheduled on the measuring machine showed two more rules, which the probes measured too: under progress override a start-to-start or start-to-finish link out of work under way is laid from the data date; a milestone keeps but never applies a constraint of its other end; a lead that lands on a close stays there as the late start; and a milestone sits no earlier than its expected finish. Engine v2.10.4 was changed to reproduce them, so the probes are fitted. H4 is the held-out test of that change: the v2.10.4 bytes and the rules of the check were committed first, naming drand round 6551257, and the twelve schedules were generated from that round after it was published and pushed before P6 saw them. P6 Professional 23.12.1 scheduled each on its own, and v2.10.4 was scored once.
233 of 237 unfinished activities match P6 on all seven fields, and ten of the twelve schedules match on every field. Run on the same schedules after the score, as a diagnosis, v2.10.3 also matches 233 of 237, and none of the 1,659 compared values moved.
| Schedule | Unfinished activities | Match on all seven fields | Result |
|---|---|---|---|
| H4-01 | 15 | 15 | every field |
| H4-02 | 30 | 30 | every field |
| H4-03 | 25 | 25 | every field |
| H4-04 | 17 | 17 | every field |
| H4-05 | 20 | 20 | every field |
| H4-06 | 22 | 22 | every field |
| H4-07 | 13 | 10 | 3 differ |
| H4-08 | 21 | 20 | 1 differ |
| H4-09 | 11 | 11 | every field |
| H4-10 | 22 | 22 | every field |
| H4-11 | 21 | 21 | every field |
| H4-12 | 20 | 20 | every field |
| Total | 237 | 233 |
H4 drew three of the progress-override links and four leads, but none where the old and new rules disagree, and no milestone with a constraint of its other end or an expected finish. So it neither confirms nor contradicts the four rules: they rest on the fitted probes, the check against the measuring machine's P6 database, and P6's own F9 of three real schedules the release moved, where v2.10.4 matches P6 on 1,747 of 1,749 activities and v2.10.3 on 657. The four activities that differ were already different in v2.10.3, and they come from two situations:
- As Late As Possible work under way under progress override whose finish-to-start successor has started (H4-08): P6 slides its remaining work to its late dates, the engine holds it at the data date;
- a Mandatory Start tied in working time with a start-to-start bound that falls on a weekend (H4-07): P6 prints the mandatory date as the late start, the engine the close before the weekend, which its seven-day predecessors carry as more negative float.
The engine is not changed against H4. A later release that changes either situation is scored on a new held-out set. The full record is in the repository's H4 result.
No held-out P6 check for v2.10.5The release changes a kind of relationship no held-out schedule can carry, 14 October 2026
Engine v2.10.5 changes one rule. A relationship that reaches the engine with a lag in days and no lag in hours, the way a time impact analysis hands its fragnet ties on, is now given its hours on the predecessor's calendar under every lag calendar, as P6 converts a lag typed in days. The P6 23.12 help says so, and two probe projects measured it in P6 Professional 23.12.1: a lag typed as one day was stored as the predecessor's ten hours under the successor and the project-default lag calendars alike. The probes are fitted.
No held-out set was drawn for this release. A held-out case is a P6 XER file, and every relationship in an XER already carries its lag in hours, so no case could exercise the change. Instead, nothing read from an XER was shown to move: no row moved in the measuring machine's P6 database (321 projects), and none of 678 XER files on the measuring machine, every H1 to H4 case among them, moved a value. H4's result stands for these bytes on its cases. The record is in the repository's changelog.
Held-out P6 check H5: 205 of 205 activities on every fieldThe engine changed to the rules H4 led to, then scored once on twelve new beacon-seeded schedules, 14 October 2026
H4's two differences were measured on four P6 probe projects: under progress override an FS or SS link into a successor already under way holds As Late As Possible work back no more than it binds the late dates, and a Mandatory Start or Mandatory Finish on work not started sets its own late date whatever its successors need, the earlier pin governing where an activity carries both. Engine v2.10.6 was changed to reproduce them, so the probes are fitted. H5 is the held-out test of that change: the v2.10.6 bytes and the rules of the check were committed first, naming drand round 6552540, and the twelve schedules were generated from that round after it was published and pushed before P6 saw them. P6 Professional 23.12.1 scheduled each on its own, and v2.10.6 was scored once.
205 of 205 unfinished activities match P6 on all seven fields, and all twelve schedules match on every field: the first held-out set with no difference. Run on the same schedules after the score, as a diagnosis, v2.10.5 also matches 205 of 205.
| Schedule | Unfinished activities | Match on all seven fields | Result |
|---|---|---|---|
| H5-01 | 9 | 9 | every field |
| H5-02 | 12 | 12 | every field |
| H5-03 | 16 | 16 | every field |
| H5-04 | 14 | 14 | every field |
| H5-05 | 21 | 21 | every field |
| H5-06 | 25 | 25 | every field |
| H5-07 | 26 | 26 | every field |
| H5-08 | 21 | 21 | every field |
| H5-09 | 19 | 19 | every field |
| H5-10 | 17 | 17 | every field |
| H5-11 | 10 | 10 | every field |
| H5-12 | 15 | 15 | every field |
| Total | 205 | 205 |
H5 drew one As Late As Possible activity and one Mandatory Start with a successor, but neither where the old and new rules disagree. So it neither confirms nor contradicts the two rules: they rest on the fitted probes and the check against the measuring machine's P6 database, where no row outside the probes moved. The engine is not changed against H5. The full record is in the repository's H5 result.
Held-out P6 check H6: 255 of 260 activities on every field, dated before 2020The day-number change scored once on twelve beacon-seeded schedules dated before or across 1 January 2020, 16 October 2026
Engine v2.10.7 counts its day numbers from 1 January 1900, so its whole-day pass keeps the dates of a schedule dated before 2020; until then that pass read every earlier date as none. H1 to H5 were all dated in 2026 and 2027, so H6 was drawn before 2020: six schedules lie wholly before it, with data dates between February 2013 and April 2017, and six started in December 2019 and run across 1 January 2020. The candidate's bytes and the rules of the check were committed first, naming drand round 6557819, and the twelve schedules were generated from that round after it was published and pushed before P6 saw them. P6 Professional 23.12.1 scheduled each on its own, and the candidate was scored once.
255 of 260 unfinished activities match P6 on all seven fields, and eleven of the twelve schedules match on every field. The five that differ are all in H6-07 and were already there in v2.10.6. They came from two situations that eight P6 probe projects then measured and the released v2.10.7 reproduces, so H6 is fitted for the release; H7 below tests it. In the whole-day pass, where the day-number change lies, the candidate put 147 of the 260 early starts on P6's calendar day; v2.10.6, run on the same schedules after the score as a diagnosis, put 55 there, and none on the six schedules dated wholly before 2020.
| Schedule | Unfinished activities | Match on all seven fields | Result |
|---|---|---|---|
| H6-01 | 24 | 24 | every field |
| H6-02 | 26 | 26 | every field |
| H6-03 | 12 | 12 | every field |
| H6-04 | 28 | 28 | every field |
| H6-05 | 25 | 25 | every field |
| H6-06 | 23 | 23 | every field |
| H6-07 | 21 | 16 | 5 differ |
| H6-08 | 30 | 30 | every field |
| H6-09 | 22 | 22 | every field |
| H6-10 | 25 | 25 | every field |
| H6-11 | 7 | 7 | every field |
| H6-12 | 17 | 17 | every field |
| Total | 260 | 255 |
The full record is in the repository's H6 result.
Held-out P6 check H7: 242 of 242 activities on every field, dated before 2020The released v2.10.7, with the two rules H6 led to, scored once on twelve new beacon-seeded schedules, 16 October 2026
H6's five differences came from two situations, measured on eight P6 probe projects: As Late As Possible work under way slides over a start-to-start or start-to-finish link out of it by only the unexpired part of the lag, and under "Calculate start-to-start lag from: Actual Start" a start-to-start link out of completed work carries no date that work carries from unfinished predecessors. Engine v2.10.7 was changed to reproduce them, so the probes are fitted. H7 is the held-out test of the released bytes: they and the rules of the check were committed first, naming drand round 6558070, and the twelve schedules, drawn as H6's were, were generated from that round after it was published and pushed before P6 saw them. P6 Professional 23.12.1 scheduled each on its own, and v2.10.7 was scored once.
242 of 242 unfinished activities match P6 on all seven fields, and all twelve schedules match on every field. The draw gave the start-to-start rule eight activities to decide, all in one schedule: v2.10.7 matches P6 on all eight, where v2.10.6, run on the same schedules after the score as a diagnosis, matches 234 of 242. Another schedule had the rule's other side, under "Early Start", where P6 keeps the carried date, as v2.10.7 does. H7 drew no case for the As Late As Possible rule, which rests on the probes.
| Schedule | Unfinished activities | Match on all seven fields | Result |
|---|---|---|---|
| H7-01 | 15 | 15 | every field |
| H7-02 | 29 | 29 | every field |
| H7-03 | 8 | 8 | every field |
| H7-04 | 14 | 14 | every field |
| H7-05 | 19 | 19 | every field |
| H7-06 | 27 | 27 | every field |
| H7-07 | 27 | 27 | every field |
| H7-08 | 37 | 37 | every field |
| H7-09 | 25 | 25 | every field |
| H7-10 | 21 | 21 | every field |
| H7-11 | 13 | 13 | every field |
| H7-12 | 7 | 7 | every field |
| Total | 242 | 242 |
The engine is not changed against H7. The full record is in the repository's H7 result.
Held-out P6 checks H8 to H15: the sets that found what v2.10.8 settlesEight sets drawn wider, each scored once, each difference measured in P6 before the next set
H8 to H15 were drawn wider than H1 to H7: resource dependent work, level of effort, WBS summary, suspended work and external dates, with about half the schedules under progress override. H8 scored the released v2.10.7; each later set scored the v2.10.8 candidate as it then stood. Each was committed before its drand round was published, drawn from that round, and scored once against P6 Professional 23.12.1's own F9 of the twelve schedules.
Every difference was then measured on synthetic P6 probe projects, 41 in all, and the engine was changed to reproduce them before the next set was drawn. So these sets are fitted for the released engine; H16 below is the held-out test of it. One rule taken on the way moved a row v2.10.7 had right; H15 caught it, and the release restores it.
| Set | Engine scored | Match on all seven fields | What its differences led to |
|---|---|---|---|
| H8 | v2.10.7, released | 247 of 248 | resource dependent work under way (RU, RF) |
| H9 | first v2.10.8 candidate | 247 of 280 | a resume date under progress override (RO), completed successors (FC, CL), total float (RT), bounds and requirements on resource dependent work (RL, RQ) |
| H10 | v2.10.8 candidate | 236 of 238 | finish requirements and leads on resource dependent work (RQ in full, RW, LC) |
| H11 | v2.10.8 candidate | 230 of 231 | start float of resource dependent work under way under retained logic (RT narrowed) |
| H12 | v2.10.8 candidate | 274 of 279 | a requirement after an expected finish (RX), the Must Finish By against a mandatory pin (MC), a bound held against the activity (RA) |
| H13 | v2.10.8 candidate | 255 of 259 | an assignment with no work left (RZ), a bound on a resource's day off (RG) |
| H14 | v2.10.8 candidate | 197 of 198 | As Late As Possible work before a completed successor (AC) |
| H15 | v2.10.8 candidate | 216 of 217 | a bound before the activity calendar opens (RB) |
Each set's full record is in the repository's held-out folder.
Held-out P6 check H16: 217 of 217 activities on every fieldThe released v2.10.8 scored once on twelve new beacon-seeded schedules
H16 is the held-out test of the released v2.10.8. The engine's bytes and the rules of the check were committed first, naming drand round 6562357, and the twelve schedules, drawn as H8 to H15 were, were generated from that round after it was published and pushed before P6 saw them. P6 Professional 23.12.1 scheduled each on its own, and v2.10.8 was scored once.
217 of 217 unfinished activities match P6 on all seven fields, and all twelve schedules match on every field. v2.10.7, run on the same schedules after the score as a diagnosis, matches 136: the rules the release adds moved 81 activities onto P6 and none away.
| Schedule | Unfinished activities | Match on all seven fields | Result |
|---|---|---|---|
| H16-01 | 6 | 6 | every field |
| H16-02 | 15 | 15 | every field |
| H16-03 | 20 | 20 | every field |
| H16-04 | 22 | 22 | every field |
| H16-05 | 30 | 30 | every field |
| H16-06 | 7 | 7 | every field |
| H16-07 | 22 | 22 | every field |
| H16-08 | 22 | 22 | every field |
| H16-09 | 14 | 14 | every field |
| H16-10 | 25 | 25 | every field |
| H16-11 | 18 | 18 | every field |
| H16-12 | 16 | 16 | every field |
| Total | 217 | 217 |
The engine is not changed against H16. The full record is in the repository's H16 result.
No new held-out P6 check for v2.10.9One rule measured on P6 probes; the sixteen held-out sets re-scored, 18 October 2026
Engine v2.10.9 changes one rule: how both passes count the part of a start-to-start or start-to-finish lag that a suspended predecessor has used up. P6 counts the working time from the predecessor's actual start to the data date less the time it sat suspended, and its backward pass counts the whole of it. Five synthetic probe projects measured the shape in P6 Professional 23.12.1, 92 of 92 rows; the probes are fitted.
No new held-out set was drawn for this release. The sixteen sets already scored were run again on the release bytes instead: all 3,741 unfinished activities still match P6 on all seven fields. A first draft of the rule moved four late dates in H13 away from P6's own F9, and the release follows P6 there. The record is in the repository's changelog.
Held-out P6 check H17: 207 of 208 activities on every fieldThe released v2.10.9 scored once; its one difference measured on P6 probes and settled in v2.10.10
H17 is the held-out test of the released v2.10.9. The engine's bytes and the rules of the check were committed first, naming drand round 6563706, and the twelve schedules were generated from that round after it was published and pushed before P6 saw them. P6 Professional 23.12.1 scheduled each on its own, and v2.10.9 was scored once.
207 of 208 unfinished activities match P6 on all seven fields, and eleven of the twelve schedules match on every field. The one difference is an early finish an hour late: resource dependent work whose start a finish requirement sets, where an assignment with no work sits after the requirement. Seven synthetic probe projects measured the shape in P6, and v2.10.10 follows P6 there.
| Schedule | Unfinished activities | Match on all seven fields | Result |
|---|---|---|---|
| H17-01 | 16 | 16 | every field |
| H17-02 | 9 | 9 | every field |
| H17-03 | 29 | 29 | every field |
| H17-04 | 21 | 21 | every field |
| H17-05 | 19 | 19 | every field |
| H17-06 | 12 | 12 | every field |
| H17-07 | 11 | 11 | every field |
| H17-08 | 9 | 9 | every field |
| H17-09 | 19 | 19 | every field |
| H17-10 | 24 | 23 | 1 differs |
| H17-11 | 11 | 11 | every field |
| H17-12 | 28 | 28 | every field |
| Total | 208 | 207 |
The engine is not changed against H17. The full record is in the repository's H17 result.
Held-out P6 check H18: 208 of 208 activities on every fieldThe v2.10.10 candidate scored once on twelve new beacon-seeded schedules
H18 is the first held-out test of the v2.10.10 candidate. The engine's bytes and the rules of the check were committed first, naming drand round 6563835, and the twelve schedules were generated from that round after it was published and pushed before P6 saw them. P6 Professional 23.12.1 scheduled each on its own, and the engine was scored once.
208 of 208 unfinished activities match P6 on all seven fields, and all twelve schedules match on every field. v2.10.9, run on the same schedules after the score as a diagnosis, also matches 208: the draw gave the new rule nothing to decide. One schedule was scheduled twice in a row in P6, with nothing changed between; the result reports it.
After the score, the release checks ran the Python engine the analysis tools compute with over every project in P6's database. On one H18 activity it printed a late finish half an hour early, where P6 and this engine agree: in two releases the Python engine alone had run one rule, RL, where no bound was taken. The Python engine was corrected, and a new cross-validation fixture, F178, pins the case.
| Schedule | Unfinished activities | Match on all seven fields | Result |
|---|---|---|---|
| H18-01 | 15 | 15 | every field |
| H18-02 | 12 | 12 | every field |
| H18-03 | 29 | 29 | every field |
| H18-04 | 28 | 28 | every field |
| H18-05 | 9 | 9 | every field |
| H18-06 | 8 | 8 | every field |
| H18-07 | 12 | 12 | every field |
| H18-08 | 25 | 25 | every field |
| H18-09 | 26 | 26 | every field |
| H18-10 | 10 | 10 | every field |
| H18-11 | 8 | 8 | every field |
| H18-12 | 26 | 26 | every field |
| Total | 208 | 208 |
The engine is not changed against H18. The full record is in the repository's H18 result.
Held-out P6 check H19: 216 of 216 activities on every fieldThe v2.10.10 release scored once on twelve schedules dated before or across 1 January 2020
H19 is the held-out test of the v2.10.10 release, drawn after both of its changes. The engine's bytes and the rules of the check were committed first, naming drand round 6563983, and the twelve schedules were generated from that round after it was published and pushed before P6 saw them. It is the first set to draw resource dependent work, level of effort, WBS summary, suspended work and external dates on schedules dated before or across 1 January 2020. P6 Professional 23.12.1 scheduled each on its own, exactly once, and the engine was scored once.
216 of 216 unfinished activities match P6 on all seven fields, and all twelve schedules match on every field. v2.10.9, run on the same schedules after the score as a diagnosis, also matches 216, and the Python engine matches P6 on all 216 of its activities.
| Schedule | Unfinished activities | Match on all seven fields | Result |
|---|---|---|---|
| H19-01 | 22 | 22 | every field |
| H19-02 | 19 | 19 | every field |
| H19-03 | 25 | 25 | every field |
| H19-04 | 19 | 19 | every field |
| H19-05 | 6 | 6 | every field |
| H19-06 | 11 | 11 | every field |
| H19-07 | 27 | 27 | every field |
| H19-08 | 13 | 13 | every field |
| H19-09 | 10 | 10 | every field |
| H19-10 | 30 | 30 | every field |
| H19-11 | 11 | 11 | every field |
| H19-12 | 23 | 23 | every field |
| Total | 216 | 216 |
The engine is not changed against H19. The full record is in the repository's H19 result.
Held-out P6 check H20: 195 of 198 activities on every fieldThe released v2.10.10 scored once; its one difference measured on P6 probes and settled in v2.10.11
H20 is the held-out test of the released v2.10.10. The engine's bytes and the rules of the check were committed first, naming drand round 6564238, and the twelve schedules were generated from that round after it was published and pushed before P6 saw them. P6 Professional 23.12.1 scheduled each on its own, and v2.10.10 was scored once.
195 of 198 unfinished activities match P6 on all seven fields, and eleven of the twelve schedules match on every field. The three differences are one: work under way with an expected finish and an As Late As Possible constraint, where P6 keeps the stored remaining duration and the engine re-sized it to the expected finish, and the two activities it drives. Three synthetic probe projects measured the shape in P6, and v2.10.11 follows P6 there.
| Schedule | Unfinished activities | Match on all seven fields | Result |
|---|---|---|---|
| H20-01 | 14 | 14 | every field |
| H20-02 | 17 | 17 | every field |
| H20-03 | 12 | 12 | every field |
| H20-04 | 8 | 8 | every field |
| H20-05 | 14 | 14 | every field |
| H20-06 | 27 | 27 | every field |
| H20-07 | 10 | 10 | every field |
| H20-08 | 14 | 14 | every field |
| H20-09 | 10 | 10 | every field |
| H20-10 | 30 | 30 | every field |
| H20-11 | 27 | 24 | 3 differ |
| H20-12 | 15 | 15 | every field |
| Total | 198 | 195 |
The engine is not changed against H20. The full record is in the repository's H20 result.
Held-out P6 check H21: 205 of 205 activities on every fieldThe v2.10.11 release scored once on twelve schedules, nine of them under "Make open-ended activities critical"
H21 is the held-out test of the v2.10.11 release, drawn after all three of its rules. The engine's bytes and the rules of the check were committed first, naming drand round 6564613, and the twelve schedules were generated from that round after it was published and pushed before P6 saw them. It is the first set to draw P6's "Make open-ended activities critical", an option no earlier version of the engine read. P6 Professional 23.12.1 scheduled each on its own, exactly once, and the engine was scored once.
205 of 205 unfinished activities match P6 on all seven fields, and all twelve schedules match on every field. v2.10.10, run on the same schedules after the score as a diagnosis, matches 190: the fifteen that moved onto P6 are open ends under the option and the work leading to them. The Python engine the analysis tools compute with matches P6 on all 205. In the capture one project outside the set was opened by mistake and closed unscheduled, and one schedule was opened a second time after its F9 and not scheduled again; the result reports both.
| Schedule | Unfinished activities | Match on all seven fields | Result |
|---|---|---|---|
| H21-01 | 18 | 18 | every field |
| H21-02 | 7 | 7 | every field |
| H21-03 | 19 | 19 | every field |
| H21-04 | 28 | 28 | every field |
| H21-05 | 13 | 13 | every field |
| H21-06 | 12 | 12 | every field |
| H21-07 | 15 | 15 | every field |
| H21-08 | 10 | 10 | every field |
| H21-09 | 16 | 16 | every field |
| H21-10 | 32 | 32 | every field |
| H21-11 | 14 | 14 | every field |
| H21-12 | 21 | 21 | every field |
| Total | 205 | 205 |
The draw gave two of the rules, no expected finish on As Late As Possible work and an expected finish against a finish constraint on work not yet started, nothing to decide; they rest on their probes. The engine is not changed against H21. The full record is in the repository's H21 result.
Held-out P6 check H22: 268 of 271 activities on every fieldThe released v2.10.11 scored once; its three differences are one shape, measured on P6 probes and settled in v2.10.12
H22 is the held-out test of the released v2.10.11, drawn to give the shapes H21 left undecided something to decide. The engine's bytes and the rules of the check were committed first, naming drand round 6564899, and the twelve schedules were generated from that round after it was published and pushed before P6 saw them. P6 Professional 23.12.1 scheduled each on its own, and the engine was scored once.
268 of 271 unfinished activities match P6 on all seven fields, and eleven of the twelve schedules match on every field. The three differences are one: work not yet started with a Mandatory Finish and an expected finish, under "Use Expected Finish Dates", whose successor needs it finished a working day before the Mandatory Finish date. P6 takes that earlier date as its late finish, where v2.10.11 kept the Mandatory Finish date, and the two activities leading to it follow. Every shape H21 gave nothing to decide is drawn here, and outside that one difference every activity they decide matches P6. Synthetic probe projects measured the shape in P6, and v2.10.12 follows P6 there.
| Schedule | Unfinished activities | Match on all seven fields | Result |
|---|---|---|---|
| H22-01 | 12 | 12 | every field |
| H22-02 | 15 | 15 | every field |
| H22-03 | 23 | 23 | every field |
| H22-04 | 25 | 25 | every field |
| H22-05 | 32 | 32 | every field |
| H22-06 | 14 | 11 | 3 differ |
| H22-07 | 26 | 26 | every field |
| H22-08 | 27 | 27 | every field |
| H22-09 | 25 | 25 | every field |
| H22-10 | 15 | 15 | every field |
| H22-11 | 22 | 22 | every field |
| H22-12 | 35 | 35 | every field |
| Total | 271 | 268 |
Its result stays as published. The rules taken after it are fitted on the probes and on H22, and H23 is their held-out test. The full record is in the repository's H22 result.
Held-out P6 check H23: 262 of 289 activities on every fieldThe first v2.10.12 candidate scored once; seven shapes found and measured on P6 probes
H23 is the held-out test of the first v2.10.12 candidate, drawn after its first four rules (XP, XC on finish milestones, MR and PC). The engine's bytes and the rules of the check were committed first, naming drand round 6565800, and the twelve schedules were generated from that round after it was published and pushed before P6 saw them. P6 Professional 23.12.1 scheduled each on its own, and the engine was scored once.
262 of 289 unfinished activities match P6 on all seven fields, and five of the twelve schedules match on every field. The four rules decided 43 activities, and 39 match P6. The 27 differences come from seven shapes, and 15 of them from one activity: resource dependent work whose resources first work on a day its own calendar has off. The released v2.10.11, run on the same schedules after the score as a diagnosis, matches 217.
| Schedule | Unfinished activities | Match on all seven fields | Result |
|---|---|---|---|
| H23-01 | 17 | 17 | every field |
| H23-02 | 31 | 30 | 1 differs |
| H23-03 | 31 | 28 | 3 differ |
| H23-04 | 28 | 25 | 3 differ |
| H23-05 | 25 | 24 | 1 differs |
| H23-06 | 14 | 14 | every field |
| H23-07 | 23 | 22 | 1 differs |
| H23-08 | 35 | 32 | 3 differ |
| H23-09 | 12 | 12 | every field |
| H23-10 | 21 | 21 | every field |
| H23-11 | 26 | 26 | every field |
| H23-12 | 26 | 11 | 15 differ |
| Total | 289 | 262 |
Its result stays as published. Synthetic probe projects measured the seven shapes; the rules taken from them are fitted on the probes and on H23, and H24 is their held-out test. The full record is in the repository's H23 result.
Held-out P6 check H24: 267 of 278 activities on every fieldThe second v2.10.12 candidate scored once; five resource dependent shapes found and measured on P6 probes
H24 is the held-out test of the second v2.10.12 candidate, drawn after the rules H23's shapes gave: a constraint in each slot, a Mandatory Start against finish-to-finish logic, mandatory dates against external dates, the free float of As Late As Possible work with and without "Calculate multiple float paths", and four rules in the hours pass, three of them for resource dependent work. The engine's bytes and the rules of the check were committed first, naming drand round 6566664, and the twelve schedules were generated from that round after it was published and pushed before P6 saw them. P6 Professional 23.12.1 scheduled each on its own, and the engine was scored once.
267 of 278 unfinished activities match P6 on all seven fields, and eight of the twelve schedules match on every field. The 11 differences come from five shapes, all resource dependent work. Outside them every activity the rules' shapes drew matches P6, and the free float of all 34 unfinished As Late As Possible activities matches, under the option and without it. v2.10.11, run on the same schedules after the score, matches 178.
| Schedule | Unfinished activities | Match on all seven fields | Result |
|---|---|---|---|
| H24-01 | 25 | 25 | every field |
| H24-02 | 16 | 16 | every field |
| H24-03 | 28 | 27 | 1 differs |
| H24-04 | 36 | 36 | every field |
| H24-05 | 25 | 25 | every field |
| H24-06 | 18 | 18 | every field |
| H24-07 | 23 | 23 | every field |
| H24-08 | 9 | 9 | every field |
| H24-09 | 33 | 32 | 1 differs |
| H24-10 | 32 | 27 | 5 differ |
| H24-11 | 19 | 19 | every field |
| H24-12 | 14 | 10 | 4 differ |
| Total | 278 | 267 |
Its result stays as published. Synthetic probe projects measured the five shapes; the rules taken from them are fitted on the probes and on H24, and H25 is their held-out test. The full record is in the repository's H24 result.
Held-out P6 check H25: 384 of 391 activities on every fieldThe third v2.10.12 candidate scored once; two resource dependent shapes found and measured on P6 probes
H25 is the held-out test of the third v2.10.12 candidate, drawn after the rules H24's shapes gave, all for resource dependent work on its resources' own hours. The engine's bytes and the rules of the check were committed first, naming drand round 6566986, and the twelve schedules were generated from that round after it was published and pushed before P6 saw them. P6 Professional 23.12.1 scheduled each on its own, and the engine was scored once.
384 of 391 unfinished activities match P6 on all seven fields, and nine of the twelve schedules match on every field. The 7 differences come from two shapes, both resource dependent work: an assignment with no work and a lag under a start-to-start bound, beside another assignment that sets a later late finish, and As Late As Possible work whose finish already sits at its slide's bound. v2.10.11, run on the same schedules after the score, matches 282.
| Schedule | Unfinished activities | Match on all seven fields | Result |
|---|---|---|---|
| H25-01 | 34 | 32 | 2 differ |
| H25-02 | 45 | 41 | 4 differ |
| H25-03 | 31 | 31 | every field |
| H25-04 | 23 | 23 | every field |
| H25-05 | 42 | 42 | every field |
| H25-06 | 29 | 29 | every field |
| H25-07 | 35 | 35 | every field |
| H25-08 | 21 | 20 | 1 differs |
| H25-09 | 36 | 36 | every field |
| H25-10 | 35 | 35 | every field |
| H25-11 | 30 | 30 | every field |
| H25-12 | 30 | 30 | every field |
| Total | 391 | 384 |
Its result stays as published. Synthetic probe projects measured both shapes; the three rules taken from them (ZF, BM and AG) are fitted on the probes and on H25, and H26 is their held-out test. The full record is in the repository's H25 result.
Held-out P6 check H26: 407 of 407 activities on every fieldThe v2.10.12 release scored once, drawn after all twenty-one of its rules, through one deviation committed before any value was compared
H26 is the held-out test of the v2.10.12 release, drawn after all twenty-one of its rules. The engine's bytes and the rules of the check were committed first, naming drand round 6567266, and the twelve schedules were generated from that round after it was published and pushed before P6 saw them. P6 Professional 23.12.1 scheduled each on its own, and the engine was scored once.
407 of 407 unfinished activities match P6 on all seven fields, and all twelve schedules match on every field. One schedule needed a deviation from the protocol, committed before any value was compared: the generator drew the same resource twice on one activity, P6's import kept only the first of the two assignments, and that schedule (37 of 37) is scored on the schedule P6 holds. The other eleven (370 of 370) are scored exactly as frozen. Run on the same schedules after the score, the candidate before the last three rules matches 391 and v2.10.11 217. The Python engine the analysis tools compute with matches P6 on all 407 once the sizing P6's F9 rewrote is set back to its import.
| Schedule | Unfinished activities | Match on all seven fields | Result |
|---|---|---|---|
| H26-01 | 25 | 25 | every field |
| H26-02 | 27 | 27 | every field |
| H26-03 | 31 | 31 | every field |
| H26-04 | 34 | 34 | every field |
| H26-05 | 51 | 51 | every field |
| H26-06 | 39 | 39 | every field |
| H26-07 | 32 | 32 | every field |
| H26-08 | 37 | 37 | every field |
| H26-09 | 32 | 32 | every field |
| H26-10 | 33 | 33 | every field |
| H26-11 | 37 | 37 | every field |
| H26-12 | 29 | 29 | every field |
| Total | 407 | 407 |
The engine is not changed against H26, and its result stays as published. The full record is in the repository's H26 result, with the deviation.
Held-out P6 check H27: 507 of 524 activities on every fieldThe released v2.10.12 scored once, drawn on the shapes it listed as not measured; five causes found and measured on P6 probes
H27 is the held-out test of the released v2.10.12, drawn on the shapes its validation listed as not measured. The engine's bytes and the rules of the check were committed first, naming drand round 6568106, and the twelve schedules were generated from that round after it was published and pushed before P6 saw them. P6 Professional 23.12.1 scheduled each on its own, and the engine was scored once.
507 of 524 unfinished activities match P6 on all seven fields, and five of the twelve schedules match on every field. All 17 start milestones with an expected finish match. The 17 differences fall under five causes: a Finish On or Before and a Mandatory Finish on work under way, an assignment with no units on work under way, a finish milestone at a 24-hour day's close before a day off, As Late As Possible resource dependent work led out start-to-start, and resource dependent work after a lagged start-to-finish link. v2.10.11, run on the same schedules after the score as a diagnosis, matches 337.
| Schedule | Unfinished activities | Match on all seven fields | Result |
|---|---|---|---|
| H27-01 | 41 | 41 | every field |
| H27-02 | 48 | 48 | every field |
| H27-03 | 40 | 40 | every field |
| H27-04 | 49 | 48 | 1 differs |
| H27-05 | 26 | 26 | every field |
| H27-06 | 34 | 33 | 1 differs |
| H27-07 | 45 | 43 | 2 differ |
| H27-08 | 51 | 49 | 2 differ |
| H27-09 | 48 | 39 | 9 differ |
| H27-10 | 36 | 35 | 1 differs |
| H27-11 | 56 | 55 | 1 differs |
| H27-12 | 50 | 50 | every field |
| Total | 524 | 507 |
Its result stays as published. Synthetic probe projects measured the five causes; the rules taken from them are fitted on the probes and on H27, and H28 is their held-out test. The full record is in the repository's H27 result.
Held-out P6 check H28: 537 of 563 activities on every fieldThe first v2.10.13 candidate scored once; six causes found and measured on P6 probes
H28 is the held-out test of the first v2.10.13 candidate, drawn after the rules H27's causes gave and the rule for the activity "Calculate multiple float paths" ends at, which was set in P6 for the five schedules that name one. The engine's bytes and the rules of the check were committed first, naming drand round 6568526, and the twelve schedules were generated from that round after it was published and pushed before P6 saw them. P6 Professional 23.12.1 scheduled each on its own, and the engine was scored once.
537 of 563 unfinished activities match P6 on all seven fields, and six of the twelve schedules match on every field. The rules taken after H27 hold on every activity they govern but one, which differs by another cause, and no activity differs by the end of the float paths. Of the 26 differences, 16 are the start float of resource dependent work in one schedule, whose options P6's own dialog had stored as "Start Float" under a code of its own, and 5 are As Late As Possible resource dependent work under a start bound, where the first reading of that rule does not hold. v2.10.12, run on the same schedules after the score, matches 501.
| Schedule | Unfinished activities | Match on all seven fields | Result |
|---|---|---|---|
| H28-01 | 57 | 57 | every field |
| H28-02 | 41 | 39 | 2 differ |
| H28-03 | 37 | 35 | 2 differ |
| H28-04 | 42 | 42 | every field |
| H28-05 | 40 | 40 | every field |
| H28-06 | 55 | 55 | every field |
| H28-07 | 55 | 38 | 17 differ |
| H28-08 | 46 | 46 | every field |
| H28-09 | 55 | 53 | 2 differ |
| H28-10 | 31 | 31 | every field |
| H28-11 | 53 | 51 | 2 differ |
| H28-12 | 51 | 50 | 1 differs |
| Total | 563 | 537 |
Its result stays as published. Synthetic probe projects measured the six causes; the rules taken from them are fitted on the probes and on H28, and H29 is their held-out test. The full record is in the repository's H28 result.
Held-out P6 check H29: 673 of 676 activities on every fieldThe second v2.10.13 candidate scored once; two causes found and measured on P6 probes
H29 is the held-out test of the second v2.10.13 candidate, drawn after the rules H28's causes gave, with the end of the float paths set in P6 for the three schedules that name one. The engine's bytes and the rules of the check were committed first, naming drand round 6569006, and the twelve schedules were generated from that round after it was published and pushed before P6 saw them. P6 Professional 23.12.1 scheduled each on its own, and the engine was scored once.
673 of 676 unfinished activities match P6 on all seven fields, and nine of the twelve schedules match on every field. The new placement of As Late As Possible resource dependent work under a start bound and the finish-floor rule hold on every activity they govern. The 3 differences fall under two shapes no probe had measured: As Late As Possible work with no work left on an activity calendar that does not work the day its resource opens, and a Mandatory Start on resource dependent work whose resource is off around it. v2.10.12, run on the same schedules after the score, matches 579.
| Schedule | Unfinished activities | Match on all seven fields | Result |
|---|---|---|---|
| H29-01 | 56 | 56 | every field |
| H29-02 | 71 | 71 | every field |
| H29-03 | 50 | 50 | every field |
| H29-04 | 43 | 43 | every field |
| H29-05 | 64 | 63 | 1 differs |
| H29-06 | 70 | 69 | 1 differs |
| H29-07 | 58 | 58 | every field |
| H29-08 | 54 | 54 | every field |
| H29-09 | 53 | 53 | every field |
| H29-10 | 48 | 48 | every field |
| H29-11 | 53 | 53 | every field |
| H29-12 | 56 | 55 | 1 differs |
| Total | 676 | 673 |
Its result stays as published. Synthetic probe projects measured both shapes and the float-type codes P6 reads; the rules taken from them are fitted on the probes and on H29, and H30 is their held-out test. The full record is in the repository's H29 result.
Held-out P6 check H30: 675 of 675 activities on every fieldThe v2.10.13 release scored once, drawn after all twelve of its rules
H30 is the held-out test of the v2.10.13 release, drawn after all twelve of its rules, with the end of the float paths set in P6 for the four schedules that name one. The engine's bytes and the rules of the check were committed first, naming drand round 6572006, and the twelve schedules were generated from that round after it was published and pushed before P6 saw them. P6 Professional 23.12.1 scheduled each on its own, and the engine was scored once.
675 of 675 unfinished activities match P6 on all seven fields, and all twelve schedules match on every field, with no deviation in what was scored. Every shape the draw gave the last rules matches P6: 12 As Late As Possible activities with no work left, 16 Mandatory Starts on resource dependent work, and every activity of the six schedules whose float type is the code P6's dialog writes for "Start Float" or the code it reads as "Start Float". Run on the same schedules after the score, the candidate H29 scored matches 625 and v2.10.12 559. The Python engine the analysis tools compute with matches P6 on all 675 once the sizing P6's F9 rewrote is set back to its import.
| Schedule | Unfinished activities | Match on all seven fields | Result |
|---|---|---|---|
| H30-01 | 48 | 48 | every field |
| H30-02 | 61 | 61 | every field |
| H30-03 | 46 | 46 | every field |
| H30-04 | 67 | 67 | every field |
| H30-05 | 56 | 56 | every field |
| H30-06 | 49 | 49 | every field |
| H30-07 | 71 | 71 | every field |
| H30-08 | 52 | 52 | every field |
| H30-09 | 65 | 65 | every field |
| H30-10 | 41 | 41 | every field |
| H30-11 | 66 | 66 | every field |
| H30-12 | 53 | 53 | every field |
| Total | 675 | 675 |
The engine is not changed against H30, and its result stays as published. The full record is in the repository's H30 result.
No held-out P6 check for v2.10.14The release changes the driver the engine records for work under way, not a date, 25 October 2026
Engine v2.10.14 changes what the engine records as the driver of an activity already under way. It now names what holds the remaining work, the same way in the JavaScript engine and the Python reference; before, it named the predecessor that would have driven the actual start, and the two engines broke ties differently. A driver trace or a longest-path chain through work under way can change. No date, float or critical flag moved in any measurement.
No held-out set was drawn for this release. A held-out case scores dates and floats, and none moved: every one is identical to v2.10.13 on 949 projects in the measuring machine's P6 database, and held-out sets H1 to H30, re-scored on these bytes in diagnosis mode, match P6 on all 8,850 unfinished activities, as before. The two engines agree on the recorded driver of all 193,868 activities of those 949 projects. The record is in the repository's changelog.
No held-out P6 check for v2.10.17The release changes no code in this engine; the skills' own Python engine counts working days faster, 9 November 2026
Engine v2.10.17 changes no code in the engine this page validates: cpm-engine.js and its
Python reference differ from v2.10.16 only in their version string. The release records the Python engine
that CPP's analysis skills and hosted tools run counting working days by whole weeks instead of day by
day, with every computed value identical: the same count on 8,206 and 15,000 randomised cases, every date
and float the same on 560 schedules from real P6 exports, and this page's 233 fixtures run against that
engine at 22189 of 22189. Those checks were made outside the repository, on code that is not in it.
No held-out set was drawn for this release: nothing computed moves. Held-out sets H1 to H30, re-scored in diagnosis mode, match P6 on 8,850 of 8,850 unfinished activities, as before. One thing a report can show differently: the DCMA-14 Critical Path Test in those skills stops at a time limit, and a test that stopped on v2.10.16 can now finish. The record is in the repository's changelog.
No held-out P6 check for v2.10.16The release withholds the driver, the longest path and the TIA impact where the hours pass disagrees; no date moves, 6 November 2026
Engine v2.10.16 checks three results that were still read off the whole-day pass, the driving predecessor, the longest path traced through the drivers and the impact figure of a time impact analysis, against the hours pass. Where the two disagree on part-day work, the result is withheld with an alert; nothing is worked out in its place. The TFM set, the activities with no float, now reads the float the hours pass prints.
No held-out set was drawn for this release: no date, float or critical flag moves. Of the 1,502 exports that schedule in the measuring machine's working folders and OneDrive, compared field by field against v2.10.15, per activity only the recorded driver moved, on 305 activities in 204 files. The longest path is withheld in 149 of them, and the TFM set changed in 339, where it now matches the critical flags. Held-out sets H1 to H30, re-scored in diagnosis mode, match P6 on 8,850 of 8,850 unfinished activities, as before; the driver is not among the fields they compare. The record is in the repository's changelog.
No held-out P6 check for v2.10.15The release reads a blank lag in an XER as a zero lag; no file on hand moves, 1 November 2026
Engine v2.10.15 changes how the XER parser reads a relationship whose lag field is blank. A P6 6.0 export leaves zero lags blank. Since v2.9.12 the parser had dropped each such relationship, with an alert naming it; it now reads the blank as a zero lag, as it did before v2.9.12. An outside user reported it, from an export the parser had cut 2,614 of 3,235 relationships from.
No held-out set was drawn for this release. None of the 1,477 exports in the measuring machine's working folders carries a blank lag, and the 1,465 of them that schedule give identical results on v2.10.14 and v2.10.15. Held-out sets H1 to H30, re-scored on these bytes in diagnosis mode, match P6 on all 8,850 unfinished activities, as before. The record is in the repository's changelog.
The other gate suitesEight checks that run alongside the cross-validation, including a client-name guard
- Unit suite. 1524 unit tests across calendar arithmetic, the forward and backward pass, topological sort, cycle detection and the public API. 0 failures.
- No fabricated citations. Scans markdown, JavaScript, HTML and Python for standards citations that do not resolve.
- No client names. Scans tracked source for client and project identifiers, so no real engagement can reach a public commit.
- No truncation. Confirms engine surfaces return complete data rather than a capped subset.
- No stale version references. Scanned 16 files, 3876 lines and 464 version references against the current engine version.
- Procedure validator. Four fixtures exercising the documented analysis procedure.
- Signing and attestation. Seven sub-suites over the cryptographic sign-off path.
- P6 comparison validator and corpus topology. Seven scenarios, one real and six synthetic, plus a topology fixture confirming the diamond-cascade shape of case 13.
The release-evidence packet for v2.9.39 was built from the release commit and passed its strict gate with all ten required files present; the v2.9.43 packet did the same (Sigstore Rekor logIndex 2685194682), the v2.9.44 packet did (CI-signed witness, Sigstore Rekor logIndex 2854361810), the v2.10.7 packet did (CI-signed witness, Sigstore Rekor logIndex 3286607165), the v2.10.8 packet did (CI-signed witness, Sigstore Rekor logIndex 3309924126), the v2.10.9 packet did (CI-signed witness, Sigstore Rekor logIndex 3312757577), the v2.10.10 packet did (CI-signed witness, Sigstore Rekor logIndex 3316054053), the v2.10.11 packet did (CI-signed witness, Sigstore Rekor logIndex 3319146213), the v2.10.12 packet did (CI-signed witness, Sigstore Rekor logIndex 3330023845), the v2.10.13 packet did (CI-signed witness, Sigstore Rekor logIndex 3386066936), the v2.10.14 packet did (CI-signed witness, Sigstore Rekor logIndex 3462156401), the v2.10.15 packet did (CI-signed witness, Sigstore Rekor logIndex 3635570997), and the v2.10.16 packet did (CI-signed witness, Sigstore Rekor logIndex 3711479435), and the v2.10.17 packet does (CI-signed witness, Sigstore Rekor logIndex 3761547375).