feat: add driving flag to relationship query responses

Add computed driving flag to all relationship queries (list_relationships,
get_predecessors, get_successors). A relationship is marked as driving when
the predecessor's early end date plus lag determines the successor's early
start date.

Changes:
- Add early_start_date and early_end_date columns to activities schema
- Parse early dates from TASK table in XER files
- Implement is_driving_relationship() helper with 24hr tolerance for
  calendar gaps
- Update all relationship queries to compute and return driving flag
- Add contract and unit tests for driving flag functionality
- Update spec, contracts, and documentation
This commit is contained in:
2026-01-07 07:21:58 -05:00
parent 2255b65ef6
commit af8cdc1d31
17 changed files with 654 additions and 324 deletions

View File

@@ -56,6 +56,8 @@ A unit of work in the schedule.
| task_type | enum | Yes | TT_Task, TT_Mile, TT_LOE, TT_WBS, TT_Rsrc |
| target_start_date | datetime | No | Planned start |
| target_end_date | datetime | No | Planned finish |
| early_start_date | datetime | No | Calculated early start (for driving computation) |
| early_end_date | datetime | No | Calculated early finish (for driving computation) |
| act_start_date | datetime | No | Actual start |
| act_end_date | datetime | No | Actual finish |
| total_float_hr_cnt | float | No | Total float in hours |
@@ -88,9 +90,23 @@ A dependency link between two activities.
| pred_task_id | string | Yes | Predecessor activity (the one constraining) |
| pred_type | enum | Yes | PR_FS, PR_SS, PR_FF, PR_SF |
| lag_hr_cnt | float | No | Lag time in hours (can be negative) |
| driving | boolean | No | **Computed** - True if this relationship determines successor's early dates |
**XER Source**: `TASKPRED` table
**Driving Flag Computation** (not stored, computed at query time):
The `driving` flag indicates whether this predecessor relationship constrains the successor activity's early start date. It is computed by comparing dates:
```python
# For FS (Finish-to-Start) relationships:
driving = (predecessor.early_end_date + lag_hr_cnt successor.early_start_date)
# With 1-hour tolerance for floating point arithmetic
```
This requires JOIN on activity dates when querying relationships.
**Relationship Types**:
| Code | Name | Meaning |
|------|------|---------|
@@ -172,6 +188,8 @@ CREATE TABLE activities (
task_type TEXT NOT NULL,
target_start_date TEXT,
target_end_date TEXT,
early_start_date TEXT, -- Used for driving relationship computation
early_end_date TEXT, -- Used for driving relationship computation
act_start_date TEXT,
act_end_date TEXT,
total_float_hr_cnt REAL,