Skip to content

Releases: danafitkowski/cpp-xer-parser

v0.2.1 — The validation report carries a summary and its worst severity

Choose a tag to compare

@danafitkowski danafitkowski released this 29 Sep 22:42

A patch release. The bundled ValidationReport serialises with the summary CPP's internal report carries, so a caller can read a report's worst severity from it.

Added

  • ValidationReport.to_dict()['summary']: block, warn, info and pass (the number of findings at each severity), total, and worst_severity, the worst severity present, ranked BLOCK > WARN > INFO > PASS, and PASS for a report with no findings. The keys and values are the internal report's, in its order. cpp-critical-path-validator reads summary['worst_severity'] from its embedded DCMA-14 report.
  • ValidationReport.worst_severity, the property the summary reads, and count() with no argument, the number of all findings.

count, worst_severity, the summary block and the severity ranking are AST-identical to the internal module without docstrings.

Nothing moves

The release adds a key, a property and an optional argument, and changes no existing value. to_dict() still carries counts and lists findings in the order they were added (the internal report sorts them worst first), and count(severity) is unchanged. xer_parser.py and config_profiles.py are unchanged.

Why a patch. Before 1.0 this project moves the minor number for a release that changes results a caller already reads, as v0.2.0 did, and the patch number for one that only adds.

Testing

tests/test_report_summary_2026_09_29.py has 9 synthetic tests; all 9 fail against v0.2.0's validation.py, and 7 mutants of the port are each killed. pytest tests/ is 109 tests across 11 files: 108 pass and the engine-parity test skips, and all 109 pass with cpp-cpm-engine's python_reference on sys.path. CI is green on Linux, macOS and Windows against Python 3.10, 3.11 and 3.12.

See CHANGELOG.md.

v0.2.0 — Calendars decode in both slot orders; working-day arithmetic, the writer and the summary are corrected

Choose a tag to compare

@danafitkowski danafitkowski released this 29 Sep 21:11

The first release since v0.1.0. Calendar decoding, working-day arithmetic, the XER writer and the schedule summary are corrected, a blank activity calendar id resolves to the project calendar, and the two validation entry points run from a plain clone.

Output changes

None of the public function signatures changed, but several results did, each from wrong to right:

  • Finding check_ids are XER-* (XER-PROJECT-MISSING, XER-CALENDAR-MISSING, XER-NO-TASKPRED and the rest), no longer AACE-31R-03-*.
  • Working-day counts and steps move on a finish-first calendar, on a worked exception day, for datetimes whose clock times differ, for half-day values, and for a zero-day step from a non-working day.
  • generate_summary: loe_count no longer counts WBS summary rows, critical_activities is the complete list, and critical_path has no note key.
  • validate_schedule raises the new activity-calendar findings.

Fixed

  • Calendar time slots decode in either field order. P6 writes a slot as (s|08:00|f|16:00) or (f|16:00|s|08:00), per calendar. Finish-first calendars decoded to no working days and were counted as Mon-Fri, and their worked exception days were filed as holidays. With it:

    • worked exceptions separated from their date by P6's line markers are no longer holidays;
    • exception dates from 1970 to 2099 are kept (the window was 1990-2050);
    • a day carrying work hours is never also a holiday.
  • Working-day arithmetic (get_work_days_between, add_work_days, subtract_work_days):

    • worked exception days (special_workdays) count;
    • both dates are read on their calendar day, so Friday 17:00 to Monday 08:00 counts both days, and a date compares with a datetime;
    • a span over 100 years returns None;
    • half-days round half-up;
    • a zero-day step snaps off a non-working day, as cpp-cpm-engine does.

    The add_work_days docstring now states the gap contract: EF = add_work_days(ES, D - 1).

  • generate_xer collapses tabs and line breaks inside values, so a value can no longer shift or split its row.

  • parse_xer keeps cells beyond a row's header under __extra_<column> keys.

  • TABLE_ORDER writes the resource-code assignment table as RSRCRCAT, the header P6 writes, and drops a phantom RISKTYPES.

  • generate_summary counts LOE and WBS summary rows separately (new wbs_count), adds a work-only completion (work_task_count, complete_work, percent_complete_work), and lists every critical activity.

  • validate_schedule and aace_31r_compliance run from a plain clone.

Added

  • Activity calendars:
    • resolve_task_calendars, with_resolved_calendars and calendar_resolution_block read a blank TASK.clndr_id as the project calendar, then the default calendar;
    • validate_schedule raises BLOCK XER-TASK-CALENDAR-UNRESOLVED and INFO XER-TASK-CALENDAR-FALLBACK;
    • generate_summary converts float on the resolved calendar;
    • get_calendar_map entries carry default_flag.

Changed

  • README:
    • a Scope section states what this package does not include: a date-field gate, a calendar-decode warning channel, and working-day arithmetic beyond get_work_days_between / duration_hours_to_days;
    • the XER generation rules give the measured field counts (PROJECT 71, SCHEDOPTIONS 25, PROJWBS 26, TASK 61, TASKPRED 11 at P6 23.10 to 24.12) in place of 72/26/27/62/12;
    • the live test badge and a version badge replace the static "stable" badge.
  • Validation findings cite the documents that govern them (AACE 29R-03, 38R-06, DCMA 14-Point #1), and seven finding messages are worded as sentences.
  • references/table-reference.md documents both time-slot orders again.
  • SECURITY.md supports 0.2.x.

Testing

  • Tests: 100 across 10 files, all on synthetic data (15 across 2 files at v0.1.0).
  • Engine parity: one test compares 6,490 add_work_days / subtract_work_days calls with cpp-cpm-engine v2.9.49. It runs when the engine's python_reference directory is on sys.path and skips otherwise.
  • CI: 9/9 green on Linux, macOS and Windows with Python 3.10 to 3.12.

Full details: CHANGELOG.md.

v0.1.0 — Initial public release

Choose a tag to compare

@danafitkowski danafitkowski released this 16 May 20:52

Initial public release. Companion to cpp-cpm-engine.

Features

  • Parse any Primavera P6 XER file into a structured Python dict with all tables, fields, and records preserved.
  • Generate valid P6 24.12 XER files from parsed or hand-built data.
  • Calendar decoding including full work-week patterns, special workdays, and holidays.
  • Cross-reference maps for WBS hierarchy, resource assignments, predecessors/successors, activity codes, and UDFs.
  • MIP 3.4 half-step XER generator (compute_half_step_xer) — AACE 29R-03 MIP 3.4 (Modelled / Additive / Multiple Base — Contemporaneous Split).
  • BOM-aware encoding detection (UTF-8 BOM / UTF-16 LE/BE BOM).
  • Schedule integrity manifest with SHA-256 source hash and AACE 31R-03 compliance scoring.
  • Schema drift detection between two parsed XERs.

Engine compatibility

Tested against cpp-cpm-engine v2.9.x (current as of 2026-05-16: v2.9.11+). The parse output is consumed by cpm-engine.parseXER() and is independent of the engine math.

Security

See SECURITY.md — 90-day coordinated disclosure, hello@criticalpathpartners.ca with SECURITY in the subject.

See CHANGELOG.md for the full v0.1.0 entry.