Repository navigation
mppread: import assignments, their resources and baselines from .mpp (#445) - #507
Conversation
…445) Decode TBkndRsc (identity, name, type, max units) and TBkndAssn (identity, units, work, dates, Baseline..Baseline10 Start/Finish/Work/Cost) against Project's own XML. Project stores no assignment baseline BCWS/BCWP, so those stay None. Adds the Project COM generator for the oracle cases. Committed by the planner: the implementer pane cannot write .git. Co-Authored-By: Codex <noreply@openai.com>
… blank rows, task-0 assignments (#445) Index TBkndRsc/TBkndAssn records by offsets, skipping kind-4 blanks and kind-2 superseded versions; store Var2Data ranges instead of per-key copies; share the task cost/work conversions; pin every baseline slot 0..10 with a generated oracle and assert COM against XML. Committed by the planner: the implementer pane cannot write .git. Co-Authored-By: Codex <noreply@openai.com>
…ks leveling inputs (#445) An unvalidated TBkndRsc/TBkndAssn stride or row shape keeps the task-only import instead of refusing; corruption inside the validated layout still refuses. Drop the with/without-resource schedule comparison (CPM never reads resources) and compare resource max units and assignment units with Project's XML instead. Refuse an assignment whose start follows its finish; fixtures now distinguish UID from ID and carry superseded rows. Committed by the planner: the implementer pane cannot write .git. Co-Authored-By: Codex <noreply@openai.com>
A header-only FixedMeta, a shorter inferred stride, or a lowered count over valid current-layout records is corruption, not an unvalidated layout. VarMeta must hold exactly its declared entries (checked on every generated and paired file). The resource name reader moves into rscdecode. Committed by the planner: the implementer pane cannot write .git. Co-Authored-By: Codex <noreply@openai.com>
#445) Committed by the planner: the implementer pane cannot write .git. Co-Authored-By: Codex <noreply@openai.com>
Resolve project.rs against #161's task-field import; keep both. Align overalloc's TBkndRsc/TBkndAssn reading with the new decoders (resource UID at +4, schema stubs, superseded and blank rows, placeholders); add the empty baseline timephased_data main's model gained. Compare IgnoreResourceCalendar with Project-exported XML only; MPXJ's 26-task-calendar disagrees with the binary bit. Committed by the planner: the implementer pane cannot write .git. Co-Authored-By: Codex <noreply@openai.com>
… exclusion to one task (#445) Committed by the planner: the implementer pane cannot write .git. Co-Authored-By: Codex <noreply@openai.com>
|
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Clippy on rustc 1.98 rejects a constant-size chunks_exact. Committed by the planner: the implementer pane cannot write .git. Co-Authored-By: Codex <noreply@openai.com>
|
Not merged automatically: condition 3 failed (merge-check on 69f5035): Cause: the Clippy step (rustc 1.98.1, all targets) reports Proposed fix: pass the Local |
Committed by the planner: the implementer pane cannot write .git. Co-Authored-By: Codex <noreply@openai.com>
|
Merged automatically (auto-merge is on for this checkout):
Follow-up filed: #508 (minor, review r1). A Scope note: |
What and why
Opening an
.mpplost every assignment baseline, becausemppreadimported no resources or assignments at all. The baselines have nowhere to live without the assignments they belong to (AssignmentBaselineexists only onAssignment, and MSPDI writes it only inside<Assignment>). This PR imports:TBkndRsc): UID, ID, name, type (work / material / cost), max units.TBkndAssn): UID, task UID (including the project summary task, UID 0), resource UID (including-65535, unassigned), units, work, start and finish.Save As MSPDI or
.yppxthen writes the<Baseline>blocks that Project itself exports.Closes #445
Baseline BCWS/BCWP: Project stores none for assignments
The issue asked for assignment baseline BCWS/BCWP too. The feasibility check showed Project has none:
<Baseline>blocks with only Number, Start, Finish, Work and Cost. BCWS and BCWP appear only at the assignment level.Assignmentobject has no BaselineBCWS or BaselineBCWP property.So a
.mpphas none to lose. They stayNone, and the generator asserts that Project's XML omits them. That assumption was carried over from the MSPDI side (#289). Assignment-level earned value, progress, rates, contours and delays stay with #342.Which tables are imported and which are refused
Oracles and tests
New generator
corpus/tools/gen_mpp_assignment_baseline_cases.py. It drives Microsoft Project over COM and writes.mppfiles plus Project's XML (git-ignored) for these cases:For every slot it asserts that the values Project reports over COM match the XML it saved.
mppread/tests/oracle_corpus.rscompares, by UID, the imported resources, assignments and every baseline slot with Project's XML: presence, dates, work, and cost and units compared as numbers. It covers the generated cases and the paired corpus cases 18-22, 24 and 25, and does an MSPDI round-trip. The existing checks of scheduled dates against Project's XML stay green.Synthetic unit tests (these run in CI without the corpus):
Commands run:
cargo test --workspace, themppread/projcore/yppxytests withMPP_PAIRED_CORPUSset,cargo clippy --workspace -- -D warningsandcargo fmt --check.Review record
The plan was agreed with Codex at v3, and there were four revmux rounds.
Round 1: six Major findings, all fixed.
0xFFFFtime sentinel was refused.I added two findings of my own. Baseline slots 2 to 9 had been extrapolated; the generator now saves all eleven slots and the test checks each one. Kind-2 assignment rows had been imported as live assignments; they are now skipped.
Four Minor and one Immaterial finding were fixed: assignment costs spelled
800.00instead of800, an error message naming the wrong cause, missing resource-decoder tests, stale crate docs, and a generator that asserted only the XML.Round 2: Minor findings, all fixed.
Round 3: Minor findings, fixed. A wrong FixedMeta count had been treated as an unvalidated layout, and a VarMeta count check that was not exact let a lowered count drop entries.
Round 4: one Minor finding, fixed and checked by reading the diff. The record-shape rule was duplicated between two index checks; they now share one helper.
Declined: two unreachable defensive error branches in
date()andmoney()(Immaterial, harmless).Known limit: COM cannot create a truly blank Resource Sheet row, so that case is covered only by the synthetic test.
Follow-up: a
.mppwith a deleted resource is refused by the existing calendar decoder. That is also true on main, and a follow-up issue is filed.🤖 Generated with Claude Code