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
102 lines
4.6 KiB
Markdown
102 lines
4.6 KiB
Markdown
# Implementation Plan: Add Driving Flag to Relationships
|
|
|
|
**Branch**: `001-schedule-tools` | **Date**: 2026-01-06 | **Spec**: [spec.md](./spec.md)
|
|
**Input**: Feature specification from `/specs/001-schedule-tools/spec.md`
|
|
|
|
## Summary
|
|
|
|
Extend the existing XER MCP Server implementation to include the "driving" flag in all relationship query responses. This requires updating the database schema, XER parser, and query functions to extract and return the driving relationship indicator from Primavera P6 schedule data.
|
|
|
|
## Technical Context
|
|
|
|
**Language/Version**: Python 3.14
|
|
**Primary Dependencies**: mcp (MCP SDK), sqlite3 (stdlib)
|
|
**Storage**: SQLite in-memory database
|
|
**Testing**: pytest, pytest-asyncio
|
|
**Target Platform**: Linux server (local MCP server)
|
|
**Project Type**: single
|
|
**Performance Goals**: Query response < 1 second, load < 5 seconds for 10k activities
|
|
**Constraints**: Single-user operation, in-memory storage for loaded XER data
|
|
**Scale/Scope**: Files up to 50,000 activities
|
|
|
|
## Constitution Check
|
|
|
|
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
|
|
|
|
| Principle | Status | Evidence/Notes |
|
|
|-----------|--------|----------------|
|
|
| I. Test-First Development | ✅ PASS | TDD required - write failing tests first for driving flag in relationship responses |
|
|
| II. Extensibility Architecture | ✅ PASS | Current design already separates parser → db → query → tool layers |
|
|
| III. MCP Protocol Compliance | ✅ PASS | Tool schemas already JSON Schema compliant; no schema changes needed |
|
|
| IV. XER Format Fidelity | ✅ PASS | Must parse `driving_flag` from TASKPRED table in XER files |
|
|
| V. Semantic Versioning | ✅ PASS | Adding new field to response is backward-compatible (MINOR) |
|
|
|
|
**Pre-design Status**: All gates PASS
|
|
|
|
**Post-design Status** (re-evaluated after Phase 1):
|
|
|
|
| Principle | Status | Evidence/Notes |
|
|
|-----------|--------|----------------|
|
|
| I. Test-First Development | ✅ PASS | Tests will verify: (1) early dates parsed from TASK, (2) driving computed correctly, (3) driving included in all relationship responses |
|
|
| II. Extensibility Architecture | ✅ PASS | Driving computation is isolated in query layer; no changes to parser or model structure |
|
|
| III. MCP Protocol Compliance | ✅ PASS | Response schema updated in contracts/mcp-tools.json |
|
|
| IV. XER Format Fidelity | ✅ PASS | Research confirmed: driving is computed from schedule dates (matching P6 behavior), not stored in XER |
|
|
| V. Semantic Versioning | ✅ PASS | Adding `driving` field is backward-compatible (MINOR version bump)
|
|
|
|
## Project Structure
|
|
|
|
### Documentation (this feature)
|
|
|
|
```text
|
|
specs/001-schedule-tools/
|
|
├── plan.md # This file
|
|
├── research.md # Phase 0 output
|
|
├── data-model.md # Phase 1 output
|
|
├── quickstart.md # Phase 1 output
|
|
├── contracts/ # Phase 1 output
|
|
└── tasks.md # Phase 2 output (/speckit.tasks)
|
|
```
|
|
|
|
### Source Code (repository root)
|
|
|
|
```text
|
|
src/
|
|
├── xer_mcp/
|
|
│ ├── models/
|
|
│ │ └── relationship.py # Add driving field to dataclass
|
|
│ ├── parser/
|
|
│ │ └── table_handlers/
|
|
│ │ └── taskpred.py # Parse driving_flag from XER
|
|
│ ├── db/
|
|
│ │ ├── schema.py # Add driving column to relationships table
|
|
│ │ ├── loader.py # Store driving flag when loading
|
|
│ │ └── queries.py # Return driving in relationship queries
|
|
│ └── tools/
|
|
│ ├── list_relationships.py # Response already uses query result
|
|
│ ├── get_predecessors.py # Response already uses query result
|
|
│ └── get_successors.py # Response already uses query result
|
|
|
|
tests/
|
|
├── contract/
|
|
│ ├── test_list_relationships.py # Verify driving flag in response
|
|
│ ├── test_get_predecessors.py # Verify driving flag in response
|
|
│ └── test_get_successors.py # Verify driving flag in response
|
|
├── integration/
|
|
│ └── test_xer_parsing.py # Verify driving flag parsed from XER
|
|
└── unit/
|
|
├── test_table_handlers.py # Test TASKPRED handler parses driving
|
|
└── test_db_queries.py # Test queries return driving flag
|
|
```
|
|
|
|
**Structure Decision**: Single project structure (existing). No new directories needed.
|
|
|
|
## Complexity Tracking
|
|
|
|
> No constitution violations. Implementation is a focused enhancement to existing architecture.
|
|
|
|
| Item | Assessment |
|
|
|------|------------|
|
|
| Scope | Small - single field addition across 4 layers |
|
|
| Risk | Low - additive change, no behavior modification |
|
|
| Testing | Contract tests + unit tests for each layer |
|