schedule-delay-analyzer

Schedule Delay Analyzer

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "schedule-delay-analyzer" with this command: npx skills add datadrivenconstruction/ddc_skills_for_ai_agents_in_construction/datadrivenconstruction-ddc-skills-for-ai-agents-in-construction-schedule-delay-analyzer

Schedule Delay Analyzer

Technical Implementation

import pandas as pd from datetime import date, timedelta from typing import Dict, Any, List, Optional from dataclasses import dataclass, field from enum import Enum

class DelayType(Enum): EXCUSABLE_COMPENSABLE = "excusable_compensable" EXCUSABLE_NON_COMPENSABLE = "excusable_non_compensable" NON_EXCUSABLE = "non_excusable" CONCURRENT = "concurrent"

class DelayCause(Enum): OWNER_CHANGE = "owner_change" DESIGN_ERROR = "design_error" WEATHER = "weather" DIFFERING_CONDITIONS = "differing_conditions" CONTRACTOR_ISSUE = "contractor_issue" MATERIAL_DELAY = "material_delay" LABOR_SHORTAGE = "labor_shortage" PERMIT_DELAY = "permit_delay" OTHER = "other"

@dataclass class DelayEvent: delay_id: str activity_id: str activity_name: str delay_type: DelayType cause: DelayCause start_date: date end_date: date delay_days: int on_critical_path: bool description: str documentation: List[str] = field(default_factory=list) cost_impact: float = 0.0

@dataclass class ScheduleBaseline: baseline_date: date planned_completion: date activities: Dict[str, Dict[str, date]] # activity_id: {start, end}

class ScheduleDelayAnalyzer: def init(self, project_name: str, contract_completion: date): self.project_name = project_name self.contract_completion = contract_completion self.baselines: List[ScheduleBaseline] = [] self.delays: Dict[str, DelayEvent] = {} self._counter = 0

def add_baseline(self, baseline_date: date, planned_completion: date,
                activities: Dict[str, Dict[str, date]]):
    baseline = ScheduleBaseline(baseline_date, planned_completion, activities)
    self.baselines.append(baseline)

def record_delay(self, activity_id: str, activity_name: str,
                delay_type: DelayType, cause: DelayCause,
                start_date: date, end_date: date,
                on_critical_path: bool, description: str,
                cost_impact: float = 0) -> DelayEvent:
    self._counter += 1
    delay_id = f"DLY-{self._counter:04d}"

    delay = DelayEvent(
        delay_id=delay_id,
        activity_id=activity_id,
        activity_name=activity_name,
        delay_type=delay_type,
        cause=cause,
        start_date=start_date,
        end_date=end_date,
        delay_days=(end_date - start_date).days,
        on_critical_path=on_critical_path,
        description=description,
        cost_impact=cost_impact
    )
    self.delays[delay_id] = delay
    return delay

def calculate_project_delay(self) -> int:
    """Calculate total critical path delay."""
    critical_delays = [d for d in self.delays.values() if d.on_critical_path]
    return sum(d.delay_days for d in critical_delays)

def analyze_by_type(self) -> Dict[str, Dict[str, Any]]:
    analysis = {}
    for delay in self.delays.values():
        dtype = delay.delay_type.value
        if dtype not in analysis:
            analysis[dtype] = {'count': 0, 'days': 0, 'cost': 0}
        analysis[dtype]['count'] += 1
        analysis[dtype]['days'] += delay.delay_days
        analysis[dtype]['cost'] += delay.cost_impact
    return analysis

def analyze_by_cause(self) -> Dict[str, int]:
    by_cause = {}
    for delay in self.delays.values():
        cause = delay.cause.value
        by_cause[cause] = by_cause.get(cause, 0) + delay.delay_days
    return by_cause

def calculate_time_extension_claim(self) -> Dict[str, Any]:
    """Calculate basis for time extension claim."""
    excusable = [d for d in self.delays.values()
                if d.delay_type in [DelayType.EXCUSABLE_COMPENSABLE,
                                    DelayType.EXCUSABLE_NON_COMPENSABLE]
                and d.on_critical_path]

    compensable = [d for d in excusable
                  if d.delay_type == DelayType.EXCUSABLE_COMPENSABLE]

    return {
        'excusable_delays': len(excusable),
        'excusable_days': sum(d.delay_days for d in excusable),
        'compensable_delays': len(compensable),
        'compensable_days': sum(d.delay_days for d in compensable),
        'total_cost_impact': sum(d.cost_impact for d in compensable),
        'recommended_extension': sum(d.delay_days for d in excusable)
    }

def get_summary(self) -> Dict[str, Any]:
    critical_delay = self.calculate_project_delay()
    projected_completion = self.contract_completion + timedelta(days=critical_delay)

    return {
        'project': self.project_name,
        'contract_completion': self.contract_completion,
        'projected_completion': projected_completion,
        'total_delays': len(self.delays),
        'critical_path_delays': sum(1 for d in self.delays.values() if d.on_critical_path),
        'total_delay_days': critical_delay,
        'by_type': self.analyze_by_type(),
        'by_cause': self.analyze_by_cause()
    }

def export_analysis(self, output_path: str):
    data = [{
        'ID': d.delay_id,
        'Activity': d.activity_name,
        'Type': d.delay_type.value,
        'Cause': d.cause.value,
        'Start': d.start_date,
        'End': d.end_date,
        'Days': d.delay_days,
        'Critical': d.on_critical_path,
        'Cost Impact': d.cost_impact,
        'Description': d.description
    } for d in self.delays.values()]
    pd.DataFrame(data).to_excel(output_path, index=False)

Quick Start

analyzer = ScheduleDelayAnalyzer("Office Tower", date(2024, 12, 31))

delay = analyzer.record_delay( activity_id="A-300", activity_name="Foundation Work", delay_type=DelayType.EXCUSABLE_COMPENSABLE, cause=DelayCause.OWNER_CHANGE, start_date=date(2024, 3, 1), end_date=date(2024, 3, 15), on_critical_path=True, description="Owner requested additional scope", cost_impact=50000 )

summary = analyzer.get_summary() print(f"Project delayed by {summary['total_delay_days']} days")

claim = analyzer.calculate_time_extension_claim() print(f"Recommended extension: {claim['recommended_extension']} days")

Resources

  • DDC Book: Chapter 3.3 - Schedule Management

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Automation

cad-to-data

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

drawing-analyzer

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

dwg-to-excel

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

cost-estimation-resource

No summary provided by upstream source.

Repository SourceNeeds Review