Summary
The Quick Start example in the README contains a subtle but impactful bug in the activity data definition. The durations list has 5 values (including one for Origin), while activities has 4 entries and predecessors has 4 entries. The comment says "First duration is for Origin" — but add_activity('O', 0) is called separately, meaning durations[0] = 0 is passed to add_activities_relations and effectively misaligns all duration-to-activity mappings by one index.
Problem
activities = ['A', 'B', 'C', 'D']
durations = [0, 2, 5, 4, 2] # 5 values — index 0 is "Origin" but Origin is already added separately
predecessors = ['-', 'A', 'B', 'B,C'] # 4 values, aligned to activities
cpm.add_activity('O', 0) # Origin already added here
cpm.add_activities_relations(activities, durations, predecessors)
# This likely maps: A→0, B→2, C→5, D→4 — and ignores the last duration (2)
# Or raises an IndexError depending on how add_activities_relations zips/iterates
This means:
- Activity
A gets duration 0 instead of 2.
- Activity
D gets duration 4 instead of 2, or the last duration is silently dropped.
- The CPM calculations (ES, EF, LS, LF, critical path) will be wrong for any network built using this example as a template.
Impact
- Every new user who runs the Quick Start example gets incorrect CPM output without any error or warning.
- The example is the primary onboarding path for the library — a silent data error here undermines confidence in the library's correctness.
- Academic users (CPM/PERT is heavily taught in operations management courses) will get wrong critical path results for their coursework.
Proposed Solution
The fix is straightforward. The durations list should only contain values for the activities, not for Origin:
activities = ['A', 'B', 'C', 'D']
durations = [2, 5, 4, 2] # 4 values, one per activity — Origin is handled separately
predecessors = ['-', 'A', 'B', 'B,C']
cpm.add_activity('O', 0)
cpm.add_activities_relations(activities, durations, predecessors)
Additionally, I would like to add a ValueError guard inside add_activities_relations to validate that len(activities) == len(durations) == len(predecessors) before processing, so future mismatches raise a clear error rather than producing silent calculation bugs.
I will fix the README example and add the validation guard. Please assign this to me.
Labels: bug, documentation, good first issue, help wanted, GSSoC 2026
Summary
The Quick Start example in the README contains a subtle but impactful bug in the activity data definition. The
durationslist has 5 values (including one for Origin), whileactivitieshas 4 entries andpredecessorshas 4 entries. The comment says "First duration is for Origin" — butadd_activity('O', 0)is called separately, meaningdurations[0] = 0is passed toadd_activities_relationsand effectively misaligns all duration-to-activity mappings by one index.Problem
This means:
Agets duration0instead of2.Dgets duration4instead of2, or the last duration is silently dropped.Impact
Proposed Solution
The fix is straightforward. The
durationslist should only contain values for the activities, not for Origin:Additionally, I would like to add a
ValueErrorguard insideadd_activities_relationsto validate thatlen(activities) == len(durations) == len(predecessors)before processing, so future mismatches raise a clear error rather than producing silent calculation bugs.I will fix the README example and add the validation guard. Please assign this to me.
Labels:
bug,documentation,good first issue,help wanted,GSSoC 2026