Connection check
verified live · 27h ago
cpp-cpm-engine
Forensic scheduling MCP for Primavera P6 (XER): AACE windows, DCMA-14, Monte Carlo, TIA.
Tools
13
GitHub stars
—
Installs / wk
—
Licence
—
Transport
streamable-http
Last checked
27h ago
Tools & capabilities
13 toolsRead from the running server on 27h ago.
claim_workbench_evidence_ledger
output_dirfolder_pathproject_namerun_forensiccontract_formevidence_files
+1
Forensic claim workbench — analyzes a folder of mixed evidence (XER chain + MSG/PDF/DOCX/XLSX correspondence) and produces a unified workbench dashboard.… Forensic claim workbench — analyzes a folder of mixed evidence (XER chain + MSG/PDF/DOCX/XLSX correspondence) and produces a unified workbench dashboard. Built from the real-world workflow where forensic delay analysis starts from a folder containing schedule updates, owner correspondence, RFIs, change orders, and meeting minutes — all mixed together. The workbench produces: - Evidence ledger (chronological): all artifacts dated and summarized - Schedule chain-diff: 14-category manipulation log (TASKPRED add/remove, constraint flips, retroactive baseline edits, completion reversals) - Rolling baseline: per-activity baseline-at-introduction across the entire XER chain - Trust score: statistical impossibilities flagged (zero-duration-variance schedules, no-new-activities, every-activity-hits-baseline, etc.) - Slip-to-evidence cross-reference: each forensic slip auto-paired with documents in its window mentioning affected activity codes - Unified HTML dashboard with all of the above Use this tool when starting forensic delay analysis from raw evidence. For single-XER-pair forensic with hand-prepared events, use ``forensic_windows_analysis`` instead. Two input modes (supply exactly one): * ``folder_path`` — a server-side evidence folder that already resolves UNDER the server temp directory (the path guard). Hosted callers cannot reach a desktop path this way. * ``evidence_files`` — a CONTENT MANIFEST: a list of ``{"name": str, "content_b64": str}`` entries carrying base64-encoded file BYTES (handles binary PDF/XLSX/MSG as well as text). The tool decodes each blob, sanitizes the filename to a bare basename (rejecting path separators, ``..``, absolute/drive paths, control chars, dot-only traversal), writes it into a FRESH per-call tempdir under the allowed server-tempdir root, runs the analysis on that staged folder, then cleans the staged dir up. Caps: at most 500 files and 60 MB total decoded bytes — an over-cap manifest returns a clear ``tool_error`` naming the cap and the actual size (NEVER silently truncated). Args: folder_path: path to the evidence folder (mode 1; must exist and resolve under the server tempdir). evidence_files: content manifest (mode 2); list of ``{"name": str, "content_b64": str}``. output_dir: optional dir for outputs (tempdir if ""). project_name: optional override. original_baseline_xer_filename: optional filename in the folder identifying the baseline XER. contract_form: contract template tag (default 'CCDC2'). run_forensic: when True (default), also runs forensic_windows_analysis on the discovered XER chain. Returns: { "evidence_ledger": {...}, "chain_diff": {...} | None, "rolling_baseline": {...} | None, "trust_score": {...} | None, "cross_reference": {...} | None, "forensic_result": {...} | None, "output_files": {...}, "errors": {...} (per-step failure log) }
collapsed_as_built
output_dirdelay_eventsproject_nameremoval_methodas_built_xer_pathcontractor_filter
+1
Collapsed As-Built / But-For analysis on a post-impact XER. Implements AACE RP 29R-03 §3.8 Modeled / Subtractive / Single Base method (paired with MIP 3.3… Collapsed As-Built / But-For analysis on a post-impact XER. Implements AACE RP 29R-03 §3.8 Modeled / Subtractive / Single Base method (paired with MIP 3.3 Windows for the dual-method gap report per SCL §11.5). Validates a forensic windows analysis (MIP 3.3) by independently computing the same project drift via subtractive removal of delays from the as-built schedule. For each delay event, the as-built duration of every ``affected_activity`` is shortened by ``impact_days`` (or removed entirely if ``removal_method="remove"``), then CPM re-runs and the resulting "but-for" finish date is compared to the as-built finish. Cumulative pass removes ALL events at once for a project-level but-for finish. Use this tool when opposing counsel demands a but-for analysis or you need a dual-method validation pairing §3.3 (windows) with §3.8 (collapsed-as-built). For prospective fragnet insertion (MIP 3.7), use ``time_impact_analysis_fragnet`` instead. Args: as_built_xer_path: server-side post-impact XER (after delays incurred). as_built_xer_content: full text of post-impact XER (alternative for hosted/remote use). Supply EXACTLY ONE of path/content. delay_events: list of event dicts. Each must have ``event_id``, ``affected_activities`` (list of task_codes), and ``impact_days`` (number). Optional: ``removal_method`` ('shorten'|'remove'), ``responsible_party``, ``name``, ``description``. output_dir: optional output dir for HTML/CSV (tempdir if ""). project_name: optional override. removal_method: global default 'shorten' or 'remove'. contractor_filter: when True, exclude contractor-caused events from the cumulative pass (owner audit mode). Returns: { "as_built_finish": "YYYY-MM-DD", "per_event_results": [{event_id, but_for_finish, impact_days_collapsed, duration_removal_basis, finish_driver_after_removal, ...}, ...], # duration_removal_basis discloses WHAT duration was removed # and on what basis; finish_driver_after_removal discloses # WHAT drives the but-for finish (incl. whether it is bound by # the data-date floor) so a reader sees WHY the finish did or # did not move across data dates. "cumulative_but_for_finish": "YYYY-MM-DD", "cumulative_impact_days": int, "dual_method_gap": dict | None, "output_files": {...}, "warnings": [...], "method": "AACE 29R-03 §3.8 (Modeled/Subtractive/Single Simulation)" }
concurrent_delay_matrix
schedulesxer_pathsxer_contents
Build the per-window x per-party concurrent-delay attribution matrix from a chronological list of XER snapshots. Implements the per-window concurrency view… Build the per-window x per-party concurrent-delay attribution matrix from a chronological list of XER snapshots. Implements the per-window concurrency view per AACE RP 29R-03 §3.3.I (apportionment) and §4.2 (concurrency). Where ``forensic_windows_analysis`` answers "how many days does each party own across the whole project?", this tool answers "how did each window distribute its shift across the parties?" — useful when defending or attacking concurrency findings on a window-by-window basis. CPP conservation check, per the AACE 29R-03 §3.3.E.13 requirement that the summed per-period net impacts equal the difference between the first schedule update and the last schedule update used in the evaluation: the sum of per-party column totals equals the sum of per-window completion shifts within ±1 day of rounding. The column-total definition is this tool's own bookkeeping, not an AACE rule. The ``conservation_check`` field on the response reflects this; ``conservation_diff_days`` carries the exact gap. IMPORTANT — conservation is NOT attribution. ``conservation_check`` can be True (the columns sum to the grand total) even when 100% of the shift lands in the Unattributed column, i.e. no party owns any of the drift. Read ``unattributed_share_pct`` and ``high_unattributed_share_warning`` to know whether a meaningful apportionment actually occurred. A fully-unattributed matrix conserves perfectly but attributes nothing — never present its green conservation check as a validated apportionment. Use this tool when you only need the matrix view; use ``forensic_windows_analysis`` for the full claim. Args: schedules: chronologically ordered list of dicts — the SAME shape ``forensic_windows_analysis`` accepts. Each dict carries ``label`` (optional) and EXACTLY ONE of ``xer_content`` (full XER text, hosted/remote use) or ``xer_path`` (server-side path, local use). This is the preferred input for hosted/remote clients. xer_paths: legacy chronologically ordered list of server-side XER file paths (local-server use). xer_contents: legacy chronologically ordered list of XER text contents. Each element is the full text of one XER. Supply EXACTLY ONE of schedules / xer_paths / xer_contents (lists must have at least 2 entries either way). Returns: { "parties": ["Owner", "Contractor", "Concurrent", "Force Majeure", "Unattributed"], # Unit for every shift_* field and the grand totals. Always # "working_days" — the matrix measures the completion shift # in working days (Dana default). The *_calendar_days twins # express the SAME shift in calendar days so an unlabeled # "11" can never be mistaken for the 15-calendar-day value. "shift_unit": "working_days", "rows": [{ "window_label", "period_start", "period_end", # shift_days == shift_workdays (working days, # legacy alias). shift_calendar_days is the same # shift in calendar days; shift_basis names the # finish driver the shift was measured on. "shift_days", "shift_unit", "shift_workdays", "shift_calendar_days", "shift_basis", "parties": {party: days}, "cascade_inferred": bool }, ...], "column_totals": {party: days}, "grand_total_shift": int, # working days (legacy) "grand_total_shift_workdays": int, "grand_total_shift_calendar_days": int | None, "conservation_check": bool, "conservation_diff_days": int, # Disambiguates "conserved AND attributed" from "conserved # but entirely Unattributed". unattributed_share_pct is # |Unattributed| / sum|shift| as a percent; the warning # flips True when that share is dominant (>= 50%). "unattributed_share_pct": float, "high_unattributed_share_warning": bool, "standard": "AACE RP 29R-03 §3.3.I (apportionment) · §4.2 (concurrency)" }
critical_path_validator
profilexer_pathxer_contentproject_indexbaseline_xer_pathbaseline_xer_content
Critical-path validation, logic health, and DCMA-14 assessment of a Primavera P6 schedule. Runs the CPP critical-path validator: checks for false… Critical-path validation, logic health, and DCMA-14 assessment of a Primavera P6 schedule. Runs the CPP critical-path validator: checks for false criticality, constraint-driven CP segments, open ends, broken logic, and surfaces a DCMA-14 block with the 14 metrics (logic, leads, lags, FS%, hard constraints, high float, high duration, invalid dates, resources, missed tasks, critical tasks, CPLI, BEI, etc.) at the chosen profile threshold (commercial / nuclear / mining). When ``baseline_xer_path`` is supplied, BEI (Baseline Execution Index) is computed. Use this tool to grade a schedule's logic health and find what should be fixed before forensic analysis. For the full HTML health-dashboard PDF render, use ``dcma14_health_check``. Args: xer_path: server-side path to the schedule XER. xer_content: full text of the schedule XER (alternative for hosted/remote use). Supply EXACTLY ONE of path/content. project_index: which project to analyze in a multi-project XER (0 = first/primary; default). profile: DCMA threshold profile - 'commercial' (default), 'nuclear', 'mining'. baseline_xer_path: optional server-side baseline XER for DCMA BEI. baseline_xer_content: optional baseline XER text content (alternative). Returns: Full validator result dict including: - 'project_name', 'data_date', 'analysis_timestamp' - 'total_activities', 'complete', activity counts - 'critical_path_findings': list of issues - 'logic_findings', 'constraint_findings' - 'overall_rating' / 'overall_score' / 'overall_confidence': LOGIC-HEALTH verdict only (open ends, logic continuity, critical-path correctness, constraints, lags). NOT a full schedule-health verdict. - 'overall_rating_scope': always 'logic_health'; 'overall_rating_label': 'Logic Health'. Use these so the headline cannot be read as full DCMA schedule-health. - 'dcma_worst_severity': the embedded DCMA-14 worst severity (BLOCK/RED/WARN/INFO/PASS) surfaced at the top level so a DCMA hard stop is visible next to the logic-health rating rather than buried in dcma_14.report.summary. - 'dcma_blocks_despite_logic_rating': True when DCMA-14 says BLOCK/RED even if the logic-health headline reads GREEN/AMBER. - 'dcma_14': dict of 14 DCMA metric results - 'recommendations': list of remediation suggestions
dcma14_health_check
debugoutput_pathtimeout_secondscurrent_xer_pathbaseline_xer_pathreturn_html_inline
+2
Full Schedule Health Dashboard HTML report — DCMA-14 + CPLI + BEI + variance/slip register against the baseline. Wraps the CPP Schedule Health Review skill… Full Schedule Health Dashboard HTML report — DCMA-14 + CPLI + BEI + variance/slip register against the baseline. Wraps the CPP Schedule Health Review skill, which produces a self-contained ~1.3 MB HTML dashboard. The dashboard renders DCMA metrics, charts, baseline-vs-current variance, slip register, GAO/AACE compliance bands, and a reproducibility manifest. Baseline XER is OPTIONAL as of Round 7 (Fix MCP-8). When omitted, the tool runs in "degraded mode": the current XER is used as its own baseline for a synthetic 0-variance run. The result carries ``degraded_mode: true`` and ``degraded_mode_reason`` explaining that BEI / variance / slip register KPIs are NOT meaningful in this mode. Supply baseline_xer_path or baseline_xer_content to get the real two-XER variance dashboard. REQUIRES Node + Playwright on the server (the dashboard renders via headless Chromium). The tool returns a clear error if either prerequisite is missing. Use this tool when you need the formal HTML deliverable. Do NOT treat ``critical_path_validator`` as a JSON view of this tool. It runs a SECOND, independent DCMA-14 implementation (``critical-path-validator/scripts/dcma14.py``) with its own criterion numbering, its own activity-eligibility rules and its own CPLI definition. Measured across the real-export corpus on 2026-08-25, the two engines return different verdicts on individual criteria for the same XER, and on some criteria they differ by construction on every file. Two separate DCMA-14 implementations, neither derived from the other. Cite one engine per matter and name which. If what you wanted was the JSON shape of THESE numbers, it is already in this tool's own return: ``dcma_14``, ``metrics`` and ``headline`` are extracted verbatim from the HTML this call produced, so they cannot disagree with the deliverable the client is reading. === HOW TO PASS THE XER FILES === For each XER (current, baseline) you supply EXACTLY ONE of: - ``*_xer_path`` — filesystem path on the server. Use this when the MCP server runs locally and the file is already accessible to it. - ``*_xer_content`` — full text of the XER file as a string. Use this when calling a HOSTED MCP server from your local Claude — the server has no access to your local filesystem, so you must send the content over the wire. The server writes it to a tempfile, runs the pipeline, and cleans up afterward. If both are supplied for the same XER, content wins (the path is ignored). If neither is supplied, the call returns an error. Args: current_xer_path: server-side path to the current XER. baseline_xer_path: server-side path to the baseline XER. current_xer_content: full text of the current XER (alternative). baseline_xer_content: full text of the baseline XER (alternative). output_path: optional output HTML path. Ignored when content is supplied (output goes to a tempdir alongside). timeout_seconds: per-step Playwright timeout (default 120s). debug: pipe Playwright stderr / browser console to stderr. return_html_inline: when True (default), the generated HTML is read off disk and returned as ``html_content`` in the response. Required for hosted/remote use; set False to save bandwidth when calling a local server where you can open ``html_path`` directly. Returns: { "ok": True, "html_path": "absolute path on the server", "html_content": "<!DOCTYPE html>..." (when return_html_inline), "current_xer": "...", "baseline_xer": "...", # ── Deliverable headline — the SAME figures the HTML # renders in its header / gauge / DCMA footer # ("GRADE C · 69% · YELLOW"). Extracted verbatim from the # dashboard's embedded payload; NOT recomputed here. These # are the authoritative grade for citing the deliverable. "grade": "C", # letter grade A-F (or None) "health_score": 69, # gauge percent = round(PASS/SCORED*100) "status_band": "YELLOW", # GREEN | YELLOW | RED "headline": { # full block (None if absent) "grade": "C", "grade_label": "Acceptable", "health_score": 69, "health_score_exact": 68.75, "status_band": "YELLOW", "passed": int, "failed": int, "scored": int, "not_scored": int, "basis": "health_score = round(passed / scored * 100); " "scored excludes not-scored criteria", }, # NOTE: result["health_score"] (the gauge percent) and # dcma_14.summary.pass_rate are now the SAME ratio on the # SAME basis — PASS / SCORED, where SCORED excludes the # unscored (status "NONE" / pass:null) criteria. So # round(dcma_14.summary.pass_rate * 100) == health_score # (e.g. 0.692 → 69), matching the HTML "69% compliance". # (Before 2026-06-28 pass_rate divided by total-criteria — # 9/14 = 0.643 — and silently contradicted the 9/13 = 69% # dashboard; that is the report-safety bug this fixed.) Cite # `health_score` / `grade` / `status_band` for the headline; # use dcma_14.summary for the raw criterion tallies. "dcma_14": { # ← sibling of html_content; # same dict SHAPE as # critical_path_validator's block. # The VALUES are this engine's and # are not interchangeable with that # tool's — see the note above. "criteria": {1: {...}, 2: {...}, ...}, # Each criterion carries `scored` (bool) and a TRI-STATE # `pass`: # "scored": True/False — did the dashboard reach a # PASS/FAIL/WARN verdict? False means the criterion # was NOT evaluated (e.g. C10 Resources when the # TASKRSRC section is absent; status "NONE"). # "pass": True — scored and PASSED # "pass": False — scored and FAILED/WARNED # "pass": null — NOT scored (no verdict). null is # distinct from false: to count failed criteria, # filter pass == False (or scored == True and not # pass), NOT pass != True — an unscored criterion is # not a failure. `summary.fail` already excludes it. # `scored` = pass + fail + warn (the dashboard's # den
forensic_windows_analysis
schedules*output_dirbaseline_idxproject_nameentitlement_milestone
Run forensic windows analysis (AACE RP 29R-03 §3.3, MIP 3.3 Observational / Dynamic / Contemporaneous As-Is) across multiple Primavera P6 XER snapshots and… Run forensic windows analysis (AACE RP 29R-03 §3.3, MIP 3.3 Observational / Dynamic / Contemporaneous As-Is) across multiple Primavera P6 XER snapshots and return the full analysis dict. This is the headline forensic tool — it computes per-window completion shifts, per-window slip registers (per-activity slip with critical/non-critical flag), per-window duration growth on critical-path activities, per-window per-party attribution (Owner / Contractor / Concurrent / Force Majeure / Unattributed), and cumulative project drift from baseline. The attribution math satisfies the CPP conservation check, per the AACE 29R-03 §3.3.E.13 requirement that the summed per-period net impacts equal the difference between the first schedule update and the last schedule update used in the evaluation (per-party day buckets sum to project drift within ±1 day, no cascade-double- counting). Use this tool for the full multi-window forensic claim. If you already have a windows result and only want the per-window × per-party grid view, call ``concurrent_delay_matrix`` instead. Args: schedules: list of dicts in chronological order. Minimum 2 entries (baseline + at least one update). Each dict must contain ``label`` (str) and EXACTLY ONE of: - ``xer_path`` — server-side filesystem path, OR - ``xer_content`` — full XER text content. Use ``xer_content`` when calling a hosted MCP server from a remote client whose XER lives locally. project_name: optional override; auto-picked from XER if "". baseline_idx: which entry in ``schedules`` is the contract baseline (default 0 = first one). entitlement_milestone: optional task_code (e.g. "Ready for Takeover") — recorded on the result, not used for math. output_dir: optional dir for HTML dashboard / DOCX report. If "", a tempdir is used and dropped after — the dashboard / report paths in the response will point to the temp location (caller responsible for moving them). Returns: { "analysis": full dict from run_windows() with keys: "windows", "cumulative", "baseline_label", "data_dates", "attribution_summary", "mcpm_attribution", ..., "dashboard": path to HTML dashboard (server-side), "report": path to DOCX executive report (server-side), "baseline_stability": {"worst_severity", "has_block", ...} } On failure: {"error": "..."} with no schedules processed.
monte_carlo_p50_p80
seedxer_pathiterationsoutput_dirxer_contentdistribution
+3
Monte Carlo Schedule Risk Analysis — P10/P50/P80/P90 completion-date forecast for a Primavera P6 schedule. Implements an AACE-style quantitative SRA (the s… Monte Carlo Schedule Risk Analysis — P10/P50/P80/P90 completion-date forecast for a Primavera P6 schedule. Implements an AACE-style quantitative SRA (the same math as CPP's browser Tool_11 Portfolio Risk Engine, scripted Python counterpart). For each iteration, every activity duration is sampled from the chosen distribution (Triangular, BetaPERT, Uniform, Lognormal, etc.) parameterized by % of baseline duration; CPM re-runs and the project finish date is recorded. After all iterations, P10/P50/P80/P90 completion dates and a sensitivity tornado (per-activity correlation to project finish) are reported. Use this tool when you need probabilistic completion forecasts or a tornado/sensitivity ranking. For the QRAMM-aligned five-level maturity badge (AACE 122R-22) on the result, pipe the response into ``qramm_maturity``. Args: xer_path: server-side path to the schedule XER. xer_content: full text of the schedule XER (alternative for hosted/remote use). Supply EXACTLY ONE of path/content. iterations: number of MC iterations (default 5000). distribution: 'Triangular', 'BetaPERT', 'Uniform', 'Lognormal' (case-insensitive — passed through). optimistic_pct, most_likely_pct, pessimistic_pct: % of baseline duration for the distribution params (defaults: 85 / 100 / 120). seed: optional fixed seed for reproducibility (0 = system entropy = non-reproducible). output_dir: optional output dir; tempdir if "". Returns: Full SRA result dict, key paths: - 'baseline.percentiles': lowercase p-keys {'p10','p25','p50','p75','p80','p85','p90','p95'}, each {'day', 'date'}. NOTE: keys are lowercase — read result['baseline']['percentiles']['p80'], not 'P80'. - 'baseline.config': sim params used - 'baseline.sensitivity': per-activity tornado rows - 'risk_register_simulation.percentiles' (only when a risk_register is supplied): SAME lowercase convention, {'p10','p50','p80','p90'} each {'day', 'date'}. - 'project_name', 'data_date', ... - HTML / DOCX paths if outputs emitted
path_explorer
xer_pathdirectionoutput_dirxer_contentinclude_near_criticaltarget_activity_codes
Logic-trace driver-chain explorer — answers "WHY is this activity critical?" and "WHAT does it drive?". Traces driving predecessors backward from a target… Logic-trace driver-chain explorer — answers "WHY is this activity critical?" and "WHAT does it drive?". Traces driving predecessors backward from a target activity to project start (the "why critical" chain) and/or driving successors forward to project finish (the "what it drives" chain). Detects constraint-driven artificial criticality and cites AACE RP 49R-06 when found. Supports multiple parallel critical paths (MCPM) and near-critical paths. Use this tool when investigating a single activity's logic chain. For a project-wide CP / logic health audit, use ``critical_path_validator``. Args: xer_path: server-side path to the schedule XER. xer_content: full text of the schedule XER (alternative for hosted/remote use). Supply EXACTLY ONE of path/content. target_activity_codes: list of task_codes to trace; if empty, all CP / near-critical endpoints are traced. direction: 'backward' (predecessors), 'forward' (successors), or 'both' (default). include_near_critical: also trace near-critical endpoints (within float band). output_dir: optional dir for HTML / CSV / JSON outputs. Returns: { "paths": [{chain dicts ...}], "output_files": {dashboard, csv, json}, "project_finish": "YYYY-MM-DD", "project_name": ..., "data_date": ... }
qramm_maturity
sra_result*
QRAMM-aligned maturity reading for an SRA result. Places a Schedule Risk Analysis run (from ``monte_carlo_p50_p80`` or any equivalent dict) on the five… QRAMM-aligned maturity reading for an SRA result. Places a Schedule Risk Analysis run (from ``monte_carlo_p50_p80`` or any equivalent dict) on the five named maturity levels of AACE RP 122R-22 (Quantitative Risk Analysis Maturity Model), section 3: level 1 Reactive, level 2 Ad-hoc, level 3 Centralized, level 4 Dynamic, level 5 Adaptive. Inputs the SRA inspects (defensively, all keys optional): - baseline.percentiles (lowercase p50 / p80 presence) - baseline.config (iterations, opt/ml/pes %, distribution) - baseline.sensitivity (per-activity tornado rows, on_cp) - mitigated (scenario comparison evidence) - risk_register_simulation + risk_register_used (Hulett quantified risk register evidence) - convergence (MC diagnostics, required for level 5) Use this tool any time you have an SRA result and want a maturity reading for a forensic-claim methodology section. Note the scope limit the badge carries on every render: AACE 122R-22 assesses the quantitative-risk capability of an ORGANIZATION and states it is guidelines rather than a standard, so a reading on one simulation run is CPP's placement on the RP's scale, not a QRAMM score. Report it as "QRAMM-aligned", never as "per AACE 122R-22". Args: sra_result: dict from ``monte_carlo_p50_p80``. May be {} - the badge degrades to level 1 with the missing evidence listed. Returns: { "rp_citation": "AACE RP 122R-22 ...", "scale_max": 5, "scale_note": "... names five levels ...", "level": int (1-5), "level_name": "Reactive" | "Ad-hoc" | "Centralized" | "Dynamic" | "Adaptive", "level_label": "Level 3: Centralized", "level_description": what CPP requires of a run there, "level_color": "#xxxxxx", "evidence": ["..." what the SRA had / lacked], "gaps_to_next_level": ["..." concrete advance steps], "caveat": scope-limit string } The keys "tier", "tier_label", "tier_description", "tier_color" and "gaps_to_next_tier" are retained as aliases carrying the same five-level values.
slip_velocity
schedulesxer_pathsxer_contents
Per-window slip velocity & acceleration trend across XER snapshots. Computes three signed metrics per window from the underlying forensic windows analysis:… Per-window slip velocity & acceleration trend across XER snapshots. Computes three signed metrics per window from the underlying forensic windows analysis: - slip_velocity_days_per_day: completion shift / window duration (positive = slipping, negative = recovering). Numerator is the WORKING-day completion shift. The denominator is WORKING days between the prior and later data dates on the same calendar (``window_duration_workdays``), making this a same-day-type working-day/working-day rate. It falls back to CALENDAR days only for legacy window dicts that predate that field, and such a row is flagged ``velocity_basis="wd/cd"``. Read ``velocity_basis`` to know which denominator produced the figure. Each velocity field name states the ratio it holds: ``slip_velocity_workdays_per_workday`` (populated only on the wd/wd path), ``slip_velocity_workdays_per_calendar_day`` (working-days of slip per CALENDAR day elapsed, computed against ``window_duration_days``), and ``slip_velocity_days_per_day`` as the retained back-compat name for whichever basis was selected. Quote ``basis`` in any expert report. NOTE (2026-09-03): the two named fields are no longer equal. ``slip_velocity_workdays_per_calendar_day`` used to be a blind copy of the headline velocity, which made its name wrong once the denominator moved to working days — it read 5/10 = 0.500 while its name promised 5/14 = 0.357. It now holds the calendar-day rate it is named for. - slip_acceleration: velocity[n] - velocity[n-1] (positive = slip rate increasing, negative = decelerating/recovery) - half_period_estimated_slip_days: shift / 2 (forensic "where were we at the midpoint" centroid estimate), in WORKING days Cumulative aggregates ``mean_velocity_days_per_day`` plus a mean per basis — ``mean_velocity_workdays_per_workday`` and ``mean_velocity_workdays_per_calendar_day`` — each computed only from the rows that actually carry that denominator, so a mean is never labelled with a basis it did not use (None when no window carried it). ``velocity_basis_set`` lists the bases present and ``velocity_units`` describes them, including an explicit MIXED string when a run spans both. Also ``max_velocity_window`` and accelerating / decelerating / recovery window counts. Honest caveats embedded in the response (mandatory for expert reports): midpoint estimates are probabilistic centroids, not observed events; velocity is per-window average, not instantaneous; acceleration is a finite difference, not a true second derivative. Built on top of AACE RP 29R-03 §3.3 windows analysis. Use this tool when you want a slip-rate trend line on top of the same per-window math ``forensic_windows_analysis`` already computes. Args: schedules: chronologically ordered list of dicts — the SAME shape ``forensic_windows_analysis`` accepts. Each dict carries ``label`` (optional) and EXACTLY ONE of ``xer_content`` or ``xer_path``. Preferred input for hosted/remote clients. xer_paths: legacy chronologically ordered list of server-side XER paths. xer_contents: legacy chronologically ordered list of XER text contents (alternative for hosted/remote use). Supply EXACTLY ONE of schedules / xer_paths / xer_contents (at least 2 entries). Returns: { "rows": [{window_label, period_start, period_end, window_duration_days, shift_days, shift_workdays, shift_calendar_days, velocity_basis, slip_velocity_days_per_day, slip_velocity_workdays_per_workday, slip_velocity_workdays_per_calendar_day, velocity_field, velocity_units, slip_acceleration, acceleration_units, midpoint_estimate_date, half_period_estimated_slip_days, half_period_estimated_slip_workdays, half_period_units}, ...], "cumulative": {mean_velocity_days_per_day, mean_velocity_workdays_per_workday, mean_velocity_workdays_per_calendar_day, velocity_basis_set, velocity_units, max_velocity_window, accelerating_windows, decelerating_windows, recovery_windows}, "units": "working-days of slip per working-day elapsed" " (wd/cd fallback wording on legacy windows; " MIXED when a run spans both)", "basis": "<numerator/denominator day-type disclosure>", "standard": "AACE RP 29R-03 §3.3 (Windows Analysis)", "caveat": "..." }
time_impact_analysis_fragnet
fragnetsoutput_dirproject_nameper_event_basesbaseline_xer_pathbaseline_xer_content
Time Impact Analysis (TIA) — prospective fragnet insertion into a pre-impact baseline schedule. Supports two modes. **Single-base mode** (legacy): supply `… Time Impact Analysis (TIA) — prospective fragnet insertion into a pre-impact baseline schedule. Supports two modes. **Single-base mode** (legacy): supply ``baseline_xer_path`` or ``baseline_xer_content``. All fragnets are inserted into the same shared baseline XER and impact is measured against that shared baseline. The result carries a ``single_base_disclosure`` warning explaining this is an AACE 29R-03 §3.7 simplification — acceptable when all events share a single baseline window, but not strict MIP 3.7 Multiple Base. **Multi-base mode** (AACE 29R-03 MIP 3.7 Multiple Base): supply ``per_event_bases`` — a dict keyed by each fragnet's ``id``, with each value a dict containing EITHER ``xer_path`` OR ``xer_content`` for that event's pre-event contemporaneous baseline. Each fragnet is inserted into its OWN base, impact is measured against THAT base's pre-event finish, and the result carries ``per_event_methodology``, ``per_event_base_count``, and ``per_event_bases_used`` (sha256-truncated content hashes for audit reproducibility). The cumulative-impact figure carries ``cumulative_caveat`` because the sum of events measured against different bases is NOT a valid joint impact. Exactly ONE of {baseline_xer_path, baseline_xer_content, per_event_bases} must be supplied. Multi-base mode errors out (returning ``{"error": ...}``) if any fragnet id is missing from ``per_event_bases``. Use this tool when modeling delay impact prospectively (e.g. quantifying RFI / change-order delay before settlement). For retrospective windows analysis after the fact, use ``forensic_windows_analysis`` (MIP 3.3 windows). Args: baseline_xer_path: server-side pre-impact baseline XER (single-base mode). baseline_xer_content: full text of pre-impact baseline XER (single-base mode, hosted/remote use). per_event_bases: dict {fragnet_id: {"xer_path": "..."} OR {"xer_content": "<full XER text>"}} for AACE MIP 3.7 Multiple Base mode. Example:: { "F1": {"xer_path": "/tmp/bl_pre_F1.xer"}, "F2": {"xer_content": "<XER text>"}, } fragnets: list of fragnet dicts. Each must have: - 'id', 'name', 'liability' (responsible party) - 'activities': list of {code, name, duration_days, calendar_id?} - 'ties': list of {pred, succ, type, lag_days?} Optional: 'description'. output_dir: output dir for TIA_Report.txt + CSV (tempdir if ""). project_name: optional override. Returns: { "report": path to TIA_Report.txt, "impacts_csv": path to TIA_Impact_Details.csv, "baseline": {"project_finish", "critical_count", ...}, "per_fragnet": [{fragnet_id, name, liability, completion_before, completion_after, impact_days, impact_working_days, affected_activities, status, error}, ...], "cumulative_days": int (sum of per-fragnet impacts), "cumulative_basis": str (BOTH modes — states the cumulative figure is the sum of independent per-fragnet impacts and overstates joint impact when fragnets share a path), "per_event_methodology": str (canonical label), "per_event_base_count": int (count of unique base XERs), "per_event_bases_used": {fragnet_id: sha256_hash8} (multi-base only), "single_base_disclosure": str (single-base only), "cumulative_caveat": str (multi-base only), }
woet_classifier
todayactual_xer_pathbaseline_xer_pathactual_xer_contentbaseline_xer_content
Worked-vs-On-time Execution Timeline (WOET) per-activity day-by-day classification of as-built execution against baseline. For each pairable activity (matc… Worked-vs-On-time Execution Timeline (WOET) per-activity day-by-day classification of as-built execution against baseline. For each pairable activity (matched by ``task_code``), classifies execution into 4 day-states: - PROGRESS: work performed during the baseline-planned window - GAIN: work performed BEFORE the baseline window opened - EXTENDED: work performed AFTER the baseline window closed - VOID: baseline-window day where activity was NOT active This is a CPP-disclosed enhancement layered on top of AACE 29R-03 §3.3 Windows Analysis — a per-day execution classifier (Progress/Gain/Extended/Void) NOT itself AACE-defined. It is not a substitute for fragnet-based AACE 29R-03 §3.7 (TIA) modeling. It gives the trier-of-fact a calendar picture of how the project executed versus how it was supposed to execute, which is otherwise buried in finish-date deltas. Use this tool when you want a per-activity execution-quality picture (on-time %, count of activities with VOID days, etc.). Args: baseline_xer_path: server-side path to baseline XER (target dates). actual_xer_path: server-side path to as-built XER (act dates). baseline_xer_content: full text of baseline XER (alternative). actual_xer_content: full text of as-built XER (alternative). Supply EXACTLY ONE of path/content per pair. today: optional ISO date (YYYY-MM-DD) reference for in-progress activities. Defaults to actual XER's last_recalc_date if available, else today's date. Returns: { "method": "WOET", "standard": "AACE 29R-03 §3.3 Windows Analysis — per-day execution classification overlay (CPP-disclosed enhancement, not AACE-defined)", "today": "YYYY-MM-DD", "project_totals": {progress, gain, extended, void}, "per_activity": [{code, name, baseline_start, ..., "dominant": str ('progress'|'gain'|'extended'|'void' or 'mixed' on a tie), "dominant_tie": bool (True when 2+ states share the top day count — do NOT assert one characterization), "dominant_states": [tied top states, never truncated]}, ...], "on_time_pct": float (0-100) }
xer_parser
xer_pathxer_content