Methods

The nine AACE RP 29R-03 Methods of Implementation, plus prospective Time Impact Analysis under RP 52R-06, which is not one of them.

Every MIP here is retrospective (Layer 1). See CONCEPTS.md §1 for the taxonomy the numbering comes from, and why "TIA", "windows analysis" and "collapsed as-built" cannot be resolved to one method.

What the engine actually runs

The taxonomy covers all nine. The engine does not.

MIP Runnable today Where
3.1 As-planned vs as-built yes forensic.static_observational.analyse_gross
3.2 As-planned vs as-built, periodic yes forensic.static_observational.analyse_periodic
3.3 Contemporaneous as-is yes cpmcore.windows.analyse
3.4 Contemporaneous split yes forensic.dynamic_observational.split
3.5 Modified or recreated yes forensic.dynamic_observational.analyse_recreated
3.6 Impacted as-planned yes cpmcore.modelled.impacted_as_planned
3.7 Impacted, multiple base yes forensic.multibase.analyse
3.8 Collapsed as-built yes cpmcore.modelled.collapsed_as_built
3.9 Collapsed, multiple base yes forensic.subtractive_multibase.analyse
Prospective TIA (RP 52R-06) yes forensic.tia.prospective_tia

All nine run. That was not true when this page was first written — it was four — and the table above is generated from the same catalogue the code uses, so it cannot drift back without a test failing.

Read "yes" precisely. It means the engine performs the method end to end and there are tests for it. It does not mean the result has been validated against Primavera or against a published analysis. Those are different claims, and the second is far weaker: see LIMITATIONS.md and engine/oracle/README.md.

Seven of the nine are reachable from the command line:

python -m forensic analyse update-06.xer update-07.xer --method 3.3
python -m forensic validate baseline.xer update-*.xer
python -m forensic concurrency update-07.xer --delays delays.json
python -m forensic tia update-07.xer --fragnet fragnet.json --delay-start 2026-05-04 --unit work_days
python -m forensic record baseline.xer update-*.xer

--method TIA refuses and prints the question separating 3.6 from 3.7, because the command line dispatches through mip.resolve and keeps no alias table of its own. MIP 3.2 and 3.5 are library-only: 3.2 needs period boundaries whose manipulability §3.2 warns about, and 3.5 needs a modification register naming what changed and on whose authority. Both refuse on the command line and name the function to call instead.

forensic.methods.catalogue() reports this table from the code rather than from this page, so it cannot drift. forensic.methods.implementation(mip) returns the callable for a runnable method and raises for one that is not, naming what is missing and which available method is nearest — deliberately not a stub, because a stub returning an empty result is indistinguishable from a real analysis that found nothing, and "the events had no critical-path effect" is a finding.

None of the above is a delay analysis on its own. Under AACE RP 29R-03 §1.5.B(1) the critical path and float must come from a validated CPM network, so run the Source Validation Protocols first (see CONCEPTS.md §7). An analysis run on an unvalidated baseline is worthless however good the engine is.


The observational methods (Layer 2: the analyst changes nothing)

MIP 3.1 — As-planned vs as-built

Observational / static logic / gross. AACE RP 29R-03 §3.1.

What it is. Compare the as-planned programme against the as-built record over the whole project as one period. Also called total time, planned vs actual, AP vs AB.

Inputs. An as-planned schedule and an as-built record. No update chain is required, which is both its appeal and its problem.

When it is the right choice. When the update chain does not exist or is not credible, and the project is small enough that a single comparison is informative. It is also the cheapest possible first pass — a way of establishing gross variance before deciding what a proper analysis would cost.

When it is wrong. Almost any time the updates exist. It has one period, so it cannot say when the time was lost, only that it was. It also cannot handle a critical path that changed during the job, which on a project long enough to be in dispute it always did.

What a tribunal makes of it. Treated as a demonstrative rather than as causation evidence. It shows variance; it does not establish that any particular event caused it. Expect it to be admitted and given little weight where the updates were available and were not used — which is exactly the point ASCE 67-17 §4.4 makes, anchoring it to Sollitt, Blinderman and Fortec.

MIP 3.2 — As-planned vs as-built, periodic

Observational / static logic / periodic. AACE RP 29R-03 §3.2.

What it is. MIP 3.1 cut into periods. One of the three things people mean by "windows analysis".

Inputs. As-planned, as-built, and a period structure. Layer 5 applies: fixed or variable/grouped periods, and that choice is itself disclosable.

When it is the right choice. When you need to locate the time in the calendar but the project has no credible update chain to take logic from. The logic stays static across every window, which is its defining property.

When it is wrong. When the updates exist. Static logic across a long project means every window is measured against a network that stopped being true after the first month.

What a tribunal makes of it. Better than 3.1 because it locates the loss in time. Still vulnerable to the same objection: the logic used is not the logic the project had.

MIP 3.3 — Contemporaneous as-is

Observational / dynamic logic / contemporaneous as-is. AACE RP 29R-03 §3.3. Also called contemporaneous period analysis, CPA, month-to-month, time slice. The SCL Protocol calls the same family a time-slice windows analysis.

What it is. Read the project's own updates and quantify the loss or gain along the driving path between consecutive data dates. The analyst inserts, removes and reshapes nothing.

Inputs. The contemporaneous update chain, in order, with data dates. That is all — and that is the constraint.

When it is the right choice. Whenever the contemporaneous updates exist and survive validation. Both AACE and the SCL Protocol make the same point about it: it is preferred when the updates exist, because it uses the critical path the project actually had at the time rather than one reconstructed afterwards by somebody who knows how the story ends.

When it is wrong. When the updates are missing, were never submitted, or were manipulated. It takes the project's own logic on trust, so a chain with revisions buried inside the progress will attribute those revisions to the work — which is precisely what MIP 3.4 exists to separate.

What a tribunal makes of it. The most readily accepted of the retrospective methods in both US and UK practice, for the reason above. Its weakness in cross-examination is the trust it places in the updates, which is why the Source Validation Protocols matter more here than anywhere else.

In the engine. cpmcore.windows.analyse. The invariant it enforces: the windows sum to the whole. Total movement from the first update's finish to the last equals the sum of the per-window movements, exactly, always. That is not a tautology — it telescopes only if every window is measured between the same pair of schedules the next one starts from, and only if the finish each window is measured against is the one the update actually reported. Skip an update, reorder two, or measure the last window against the baseline, and it stops holding. Those are the mistakes the module exists to make impossible. An analysis whose parts do not sum to the whole is an opinion with numbers attached.

Critical path changes between windows are surfaced rather than smoothed. A path that switches in window 6 is usually the fact the whole claim turns on, and it is invisible in a finish-date table because the finish can be unchanged while the work driving it is entirely different.

MIP 3.4 — Contemporaneous split (bifurcated)

Observational / dynamic logic / contemporaneous split. AACE RP 29R-03 §3.4; procedure at SVP 2.3.D.2. Also called bifurcated CPA, half-stepped or two-stepped update analysis.

What it is. MIP 3.3, but each update's variance is split into what the work did and what somebody changed about the plan. The half-step H1 is the earlier update with only the progress from the later one applied — actual dates, increased percent complete, decreased remaining duration — recalculated at the later data date. Movement from the earlier update to H1 is progress; movement from H1 to the later update is revision.

Inputs. Consecutive update pairs with data dates. Nothing external.

When it is the right choice. When the update chain contains revisions — added activities, changed logic, altered durations, new constraints — mixed in with the progress, which on a real project it always does. It is the only observational method that separates the two.

When it is wrong. When there are no revisions to separate, in which case it reduces to 3.3 with extra steps. It is also more expensive to explain: two numbers per window instead of one.

What a tribunal makes of it. Persuasive where the other side's case depends on movement that turns out to be revision rather than performance. The decomposition is checkable arithmetic, which is unusual in this field.

In the engine. forensic.svp.bifurcate performs one update pair. It recalculates all three schedules with the same options rather than reading each snapshot's stored result, because two of three finishes coming from one scheduler and the third from another would put a settings difference into the decomposition and call it a revision. The one judgment it will not make: a progress variance larger than the update period is either a revision that leaked into H1 or a legitimate calendar-driven push into a no-work period, and the RP gives no rule to tell them apart — so it is raised, not resolved.

Note that MIP 3.4 proper is this procedure applied to every update in the chain. The engine gives you the per-pair primitive, not the chain-level runner.

MIP 3.5 — Modified or recreated updates

Observational / dynamic logic / modified or recreated. AACE RP 29R-03 §3.5. Also called reconstructed or modified update analysis.

What it is. The update chain, corrected or reconstructed by the analyst before being read.

Inputs. Whatever updates survive, plus the analyst's corrections and the record justifying each one.

When it is the right choice. When the chain exists but is defective in ways that can be identified and fixed — a missing update reconstructed by de-statusing a later one, a demonstrable logic error corrected.

When it is wrong. As soon as the corrections stop being demonstrable. Every edit is an argument the analyst has to win.

What a tribunal makes of it. This is where ASCE 67-17 Chapter 10 lives, and it is unforgiving. §10.1: contemporaneous CPM schedules are presumed correct, and the burden lies on whoever changes them. §10.2: after-the-fact changes are minimised and justified by significant error. §10.3: every change is identified and documented. §10.4: correction is preferred to abandoning a flawed schedule. §10.5 draws a bright line — physical and contractual constraints may be corrected; the contractor's own preferential sequencing may not, and on federal work that narrower boundary governs over AACE's broader toolkit.

The tool supports this method by checking the analyst rather than by running it: the asce.rectifications term drives rules 10.1 through 10.5, and an empty list is an answer ("none were made") rather than a missing input.


The modelled methods (Layer 2: the analyst alters the network)

Modelled and observational methods must not be mixed in one analysis. That is how a conclusion acquires support its inputs do not give it, and it is why the engine keeps them in separate modules that name themselves in every result.

MIP 3.6 — Impacted as-planned

Modelled / additive / single base. AACE RP 29R-03 §3.6. Also called IAP, impacted baseline, and — ambiguously — "TIA".

What it is. Insert delay-event fragnets into the as-planned programme and report what the finish becomes. It answers: if these events had happened to the plan, when would it have finished?

Inputs. The as-planned schedule, and one fragnet per delay event with a duration and an attachment point. Layer 5 applies: global insertion (all fragnets at once) or stepped (one at a time, rescheduling between each). That choice is material — five fragnets inserted together and five inserted one by one give different answers whenever two of them interact, which is exactly the case where the answer is contested.

When it is the right choice. When there is genuinely no update chain, the project is short, and the delays are few and non-interacting. It is also the method the contract sometimes prescribes, in which case the argument is over.

When it is wrong — and it is widely held to be wrong. This is the most criticised method in the taxonomy and the documentation should say so plainly.

The objection is structural, not a matter of execution. The method measures every event against a plan that never changed, so:

ASCE 67-17 §4.1 and §4.4 bear directly on it: the critical path is dynamic and must be evaluated as it existed during each delay, and delay is measured by the change to the scheduled completion date. MIP 3.6 does neither. The pack groups 3.1, 3.2, 3.6 and 3.8 as the static single-base methods that the Sollitt / Blinderman / Fortec line tells against when a genuine update chain exists, and reports their use in that situation as an OBSERVATION — because ASCE flags it and does not forbid it.

What a tribunal makes of it. Commonly admitted, commonly discounted, and a reliable target in cross-examination when the updates existed and were not used. Where it is used, the analysis has to be prepared to defend the baseline as achievable and to address concurrency by some other route entirely.

In the engine. cpmcore.modelled.impacted_as_planned. Each event is inserted as a predecessor of the activity it impacts, finish-to-start, which is what "this held that up" means in a network and is the only attachment that needs no further assumption. Inserted activities carry a DELAY:: prefix so they can never collide with a real activity id and a reader can see at a glance what was added. An onset date is available and matters: without one, an event is free to float back to the data date, which understates its impact.

The result reports each event's impact on its own and the impact of all of them together, with the difference named concurrency_days. Insert two delays separately and each may push the finish five days; insert them together and the finish may move five, not ten. Reporting only the sum is making the claimant's case rather than measuring. But see CONCEPTS.md §5: that residual is evidence of concurrency, not a finding of it.

MIP 3.7 — Impacted, multiple base

Modelled / additive / multiple base. AACE RP 29R-03 §3.7. Also called time impact evaluation, and the other thing people mean by "TIA".

What it is. MIP 3.6's technique, but each fragnet is inserted into the contemporaneous update current when that event occurred, not into one fixed base.

Inputs. The full update chain, plus a fragnet per event, plus the mapping of each event to the update that was current at the time.

When it is the right choice. When you need a modelled, additive answer and the update chain exists. It answers the causation question against the schedule the project actually had, which removes most of the objection to 3.6.

When it is wrong. When the updates are missing or not credible — then you are back to 3.6 and its problems. It is also substantially more work, because it is one insertion exercise per event rather than one for the project.

What a tribunal makes of it. Better received than 3.6 for the same reason 3.3 is better received than 3.1: it uses the contemporaneous critical path. Retrospective 3.7 is still vulnerable to the criticism that fragnet durations were chosen with hindsight.

In the engine. forensic.multibase.analyse. Each event is matched to the latest update whose data date is on or before the event's onset — never a later one, which already reflects the event's consequences and would count it twice.

Three refusals worth knowing before you run it. An event with no onset date is rejected outright, because any fallback rule would place a delay in a window it may not belong to, and the neighbouring window is very often the other party's. An event predating every update supplied is returned as unmatched rather than absorbed into the earliest base — doing otherwise would be 3.6 performed under a 3.7 label. And the total is withheld when the updates used do not form a complete consecutive chain: the per-window impacts only sum to a defensible extension of time because each base has already absorbed the period before it, and skipping an update between two that were used leaves that period's movement in no window at all. total_days is then None, not zero, with chain_note naming the update that was skipped.

MIP 3.8 — Collapsed as-built

Modelled / subtractive / single simulation. AACE RP 29R-03 §3.8. Also called but-for, as-built less delay, CAB.

What it is. Take the as-built programme, remove the delay activities, and reschedule. It answers: but for these events, when would it actually have finished? Layer 5 applies: global or stepped extraction.

Inputs. A logic-bearing as-built network — which is the hard part. An as-built with no logic in it cannot be collapsed, and most as-builts are records of dates rather than networks. Building the logic is the analyst's work and is the method's principal vulnerability.

When it is the right choice. When you have a defensible as-built network and no credible contemporaneous chain, and the argument is genuinely counterfactual. It has a real advantage over 3.6: it starts from what actually happened rather than from a plan.

When it is wrong. When the as-built logic was constructed by the analyst after the fact — because then the counterfactual is being computed from a network the project never had, and the other side will spend its cross-examination on how that network was built. Also wrong where the collapse depends on removing activities whose removal changes what was driving, which is a judgment about the counterfactual rather than an arithmetic result.

And wrong where the as-built model is not logic-driven, which is §3.8.E.1 and the method's own first minimum protocol: the model's computed early dates must reproduce its recorded actual dates, because otherwise what it computes with the delays removed is a counterfactual about a network the project never had. MIP 3.8's entry point now runs that test on every result, and a failure withholds total_days and concurrency_days from the payload while publishing the analysis and the activities that failed. A model recording no actuals at all reports NOT_EVALUATED, which is not a pass and withholds nothing: it is the ordinary outcome for a network of durations and logic, and refusing on it would report None for every schedule this engine can presently build. §3.8.E.5 is tabulated alongside it — the predecessor/successor pairs the extraction left with no route between them, a table and not a gate, because a plain chain always severs. engine/quality/MIP-COVERAGE.md §8 named the wiring; engine/tests/test_collapse_gate_wiring.py is it.

No file in this repository passes that test, and the sweep is the finding. Of the 69 corpus schedules, 66 schedule at all; 48 of those record no actual dates and report NOT_EVALUATED; the remaining 18 all report FAIL. That includes the one as-built in the corpus, at 116 of 118 recorded dates not reproduced, and the shipped example demo/outputs/synthetic-800.xer at 511 of 532. Zero PASS. So the repository holds no collapsible as-built to demonstrate the method on, the shipped 3.8 example demonstrates the mechanics on a file the method's own first minimum protocol excludes, and the first run of MIP 3.8 against a model that satisfies §3.8.E.1 will be a customer's. What one would look like is an as-built whose logic and durations recompute its recorded dates — built by an analyst as part of the analysis, which is what makes it the method's principal vulnerability and not a data-collection exercise.

What a tribunal makes of it. Accepted where the as-built logic is independently supportable, attacked where it is not. Its reputation is better than 3.6's and worse than 3.3's.

In the engine. cpmcore.modelled.collapsed_as_built — labelled 3.8 in the output string, which is right: it collapses once. It was labelled 3.9 until it was cross-checked against the taxonomy, and its docstring records the correction, because a report citing 3.9 claims a period-by-period analysis it did not perform. It refuses to run with no events, and refuses events that are not present in the as-built network (that is what 3.6 is for). Actual dates are stripped from the collapse, and that is not a detail: an as-built activity carries the date it really happened, and the whole point of removing a delay is to ask when the work would have happened instead. Leaving the actuals in pins every activity exactly where it was and the collapsed network reports no change at all — a nil result that looks like a finding.

MIP 3.9 — Collapsed, multiple base

Modelled / subtractive / multiple base simulation. AACE RP 29R-03 §3.9. Also called look-back window, windows but-for, windows collapsed as-built.

What it is. MIP 3.8 performed period by period rather than once over the whole project.

Inputs. As 3.8, plus a period structure and an as-built state per period.

When it is the right choice. When a single collapse would be misleading because the driving path changed during the job — which, again, on a long project it did.

When it is wrong. Everywhere 3.8 is wrong, plus the additional cost of doing it repeatedly.

What a tribunal makes of it. The most defensible of the subtractive family, and the least often performed, because the as-built logic problem is multiplied by the number of periods.

In the engine. forensic.subtractive_multibase.analyse, wired into the analyse subcommand. This paragraph denied that for a while, contradicting the table at the top of this same page, which said yes and was right.

Three of §3.9's seven minimum protocols are conditions on the models rather than on the subtraction, and they now run. §3.9.E.1, the logic-driven test above, per period — a model that fails it withholds both totals. §3.9.E.3's qualifier: the RP asks for one partially progressed model and one fully progressed one, where the engine previously enforced only the count. §3.9.E.5's tabulation of the logic each extraction severs. The other four, including §3.9.E.6's constructability analysis, are declared NOT_EVALUATED by name in the payload with the input that would settle each; constructability is refused outright because the RP requires the analysis and defines no test for it, and printing a verdict would invent a criterion and attribute it to AACE. engine/quality/MIP-COVERAGE.md (../engine/quality/MIP-COVERAGE.md) §8 carries the before-and-after table and the fuzzing that backs each rule.


Prospective Time Impact Analysis — AACE RP 52R-06

This is not a forensic method, and the tool makes that structural rather than a matter of the analyst's care.

RP 52R-06 is a change-management tool (TCM 10.2/10.3). It is run while the job is live, days after the event, to support a contemporaneous request for a contract time extension — and the RP says so in terms, naming RP 29R-03 as the place retrospective TIA belongs. All nine MIPs are retrospective. A prospective TIA is none of them, so the result carries timing = PROSPECTIVE and asking it for a MIP code raises. A prospective TIA filed as MIP 3.6 is a category error: the same technique, a different evidentiary posture, and a different standard governing what the number is allowed to claim. A report that can print a MIP code for it will eventually print one.

What is shared with the modelled methods, and what is not

The mechanic is shared — a fragnet is spliced into a CPM base and the finish movement measured — so the insertion machinery is reused wholesale rather than reimplemented. One splice, one set of rules about which relationship types survive a reroute, one place to fix a bug.

The postures are not shared:

The eight steps, and who decides each

Every step records what it did, what it assumed, and — on the same DETERMINISTIC/HYBRID/JUDGMENT axis the conformance packs use — whether the tool decided it or a person did. A TIA is read, not run: the owner's reviewer follows the steps and stops at the first one they disagree with, so a result reporting only a number is unreviewable however correct the number is.

Step What it does
1 Model the event with a fragnet. JUDGMENT. The tool refuses to proceed on a fragnet that has not been accepted — the RP's flow chart loops back to Step 1 until it is, and Steps 2–8 are defined on an accepted fragnet. The owner reviews the logic, durations and revisions before any impact is computed, so that time is not negotiated as a function of cost.
2 Select the base schedule: the last owner-reviewed update statused before the delay. Named departures are refused with the citation.
3(a) The zero-duration gate. Set every fragnet duration to zero and require every computed date to match the unimpacted schedule. This is the standard's own built-in correctness check, and the tool treats it as a hard gate: a fragnet that fails it does not proceed.
3(b) Optional re-statusing. Not performed by the tool — that is the analyst editing the update, and the honest way to express it is to supply the re-statused schedule as the base with the edits documented. What the tool enforces is the RP's actual requirement: when 3(b) applies a statement exists, and when it is skipped the reason is recorded.
4 Insert the fragnet at its agreed durations and reschedule.
5 Measure at the contract milestone. JUDGMENT where the milestone is not named: the RP wants "the last project or contract milestone prior to demobilization", and which activity that is comes from the contract, so the tool takes the latest early finish and refers the choice.
6 The modelled time impact, in the stated unit.
7 The modelled dates of the delay, in order.
8 Strike out dates already awarded. What remains is the extension claimed.

An ambiguity resolved, named because a reviewer may disagree. Step 3(a) says to zero the fragnet durations and requires every computed date to match. It does not say what to do with a constraint carried on a fragnet activity. The tool suspends onset constraints for the gate and reinstates them for Step 4: an onset date is a statement about when the event happened, not about how the fragnet is wired, and the RP's test targets wiring ("corrections to the inserted fragnet activities may be necessary"). Left in, the gate would fail every fragnet whose event cannot start at the data date — which is most of them — and a gate that always fires is a gate nobody keeps.

When it is the right choice

Contemporaneously, while the job is live, to support a time extension request under a contract that provides for one. That is what it is for.

When it is wrong

After completion. Then it is retrospective by point of view whatever technique it uses, and it belongs under 29R-03 as MIP 3.6 or 3.7 with all of 3.6's problems. It is also wrong wherever the contract prescribes a different procedure, because 52R-06 is a Recommended Practice and the contract is a contract.

What a tribunal makes of it

Where it was genuinely performed contemporaneously and submitted at the time, it carries the weight of a contemporaneous document — which is considerable, and is most of its value. Where it was produced years later and presented as though contemporaneous, that is the first thing the other side will establish.

What it does not decide

Excusability and compensability. responsibility is carried through from each delay event untouched, because it is settled by the contract, not by a critical path. RP 52R-06 is more pointed still: it separates time from cost deliberately, and states that an excusable delay is granted regardless of a concurrent contractor cause unless the contract precludes it. The engine supplies days; the contract supplies entitlement.


Choosing, in one table

You have You want to know Use
A credible update chain Where the time went 3.3, or 3.4 if revisions are mixed into the progress
A credible update chain, and specific events to price What each event caused 3.7
A live job and a change order What extension to ask for now RP 52R-06 prospective TIA
No updates, a defensible as-built network What would have happened but for the events 3.8, or 3.9 if the driving path changed
No updates, no as-built logic, a short job A gross variance figure 3.1 or 3.2, and expect it to be discounted
No updates and a contract that prescribes it What the contract prescribes 3.6, and prepare to defend the baseline
A defective update chain you can demonstrably fix Where the time went 3.5, and read ASCE 67-17 Ch. 10 first

Whatever you choose, the method is itself an argument to be made and defended. That is the RP's position, not this tool's — and it is why a Construct report with no declared method says so on its first page rather than leaving the section blank.

Source: docs/METHODS.md. Source commit date: 2026-09-06.

See it in practice

Follow the evidence, from the schedule to the finding.

Explore the worked example