A construction scheduling engine that refuses to guess.
Multi-calendar CPM with all four relationship types and all ten Primavera constraint types; DCMA 14-point assessment; forensic delay analysis to AACE 29R-03; Primavera XER, Primavera P6 XML and MS Project MSPDI interchange. The engine imports nothing but the Python standard library, so it can be copied into another codebase and run there unchanged.
core/, pure stdlibMost scheduling tools compute a plausible answer when they should refuse. A Primavera importer that drops the relationships still produces a schedule — one where every activity is critical with zero float, and nothing says so. A float figure clamped at zero hides the fact that a date cannot be met. A forecast that quietly disagrees with the activity table below it is read against a contract date anyway.
Negative float is an output, not an error. It is never clamped — not total float, not free float. Every coercion, default or dropped row emits an issue naming what was done and why.
| Area | Capability |
|---|---|
| Scheduling | Multi-calendar CPM on an absolute ordinal time axis; FS/SS/FF/SF with lags in a chosen lag calendar; ten constraint types; data date, actuals, retained logic and progress override |
| Quality | DCMA 14-point with tri-state results — a check that could not run is skipped, not passed, and is excluded from the score's denominator |
| Risk | Seeded Monte Carlo, byte-identical between runs; criticality index and duration sensitivity |
| Resources | Demand held level per day, over-allocation per day, serial levelling within float or extending the finish |
| Forensics | Baseline comparison with delay attribution that sums exactly; contemporaneous windows analysis (MIP 3.3); impacted as-planned and collapsed as-built (MIP 3.6 and 3.9) with concurrency reported |
| Production | Line of balance with crew continuity; takt planning; Last Planner with a PPC denominator that cannot shrink after the week |
| Planning | Earned Schedule; weather allowance modelled in the calendar; schedule compression as priced options; multi-project portfolios with links across the boundary |
| Interchange | Primavera XER, Primavera P6 XML (including baselines), MS Project MSPDI — all read and written |
Passing tests prove that code does what its author expected. They do not prove the expectation was right. So the engine is also probed with generated inputs — random networks, random re-baselines, random progressed schedules — checked against the properties the modules claim rather than against remembered answers.
Those runs have found defects a fully green suite was passing over: float overstated behind a Start-to-Finish link, a Monte Carlo forecast a day late and landing on Saturdays, a Primavera constraint read as a one-sided floor so that pinned activities silently gained slack, a levelling pass that delayed an activity without delaying anything downstream of it, and an exporter that let an activity name forge a row in the file a planner opens.
Every fix is verified the same way: break the fix, watch a test go red, put it back. Where a probe found nothing, the existing tests were deliberately broken to confirm the coverage was real rather than absent — and more than once the probe turned out to be wrong before the engine was, which is recorded in the probe rather than quietly corrected.
from datetime import date
from massingplan.core.network import Link, RelationType, Task
from massingplan.core.schedule import schedule_network
tasks = [Task("A", "Substructure", 10, "5D"),
Task("B", "Frame", 15, "5D")]
links = [Link("A", "B", RelationType.FS, 0)]
outcome = schedule_network(tasks, links, calendars, data_date=date(2026, 6, 1))
print(outcome.project_finish, outcome.longest_path)
Fifteen endpoints under /api/massingplan/v1/, every one taking
and returning plain JSON: schedule, analyse,
risk, linear, takt,
level, compare, windows,
earned-schedule, modelled-delay,
compress, portfolio, weather,
import and capabilities.
curl -X POST https://your-host/api/massingplan/v1/schedule \
-H "Authorization: Bearer mpln_..." \
-H "Content-Type: application/json" \
-d '{"data_date": "2026-06-01",
"activities": [{"id": "A", "duration_days": 10}]}'
massingplan/core/ imports nothing outside the standard library,
enforced by an import-linter contract and a dedicated CI job. It is copied
verbatim into a consumer with a VENDOR.md pinning the upstream
commit, and travels with a stdlib-only conformance gate the consumer can run.