124 lines
5.3 KiB
Python
124 lines
5.3 KiB
Python
"""Scenario: EWR Crew Duty Limit — complex Part 117 crew swap needed.
|
|
|
|
Captain hitting duty limit in 2h, backup crew needed. Tests Handover IMMEDIATE action.
|
|
"""
|
|
|
|
from datetime import datetime, timezone
|
|
|
|
from mcp_servers.data.models import (
|
|
CrewMember,
|
|
CrewRole,
|
|
DelayCause,
|
|
FlightData,
|
|
FlightStatus,
|
|
MELItem,
|
|
MPStatus,
|
|
Passenger,
|
|
RebookingCase,
|
|
)
|
|
|
|
SCENARIO_ID = "crew_swap_ewr"
|
|
SCENARIO_NAME = "EWR Crew Duty Limit"
|
|
SCENARIO_DESCRIPTION = (
|
|
"Captain on UA2180 hitting Part 117 duty limit in 1h 45min. "
|
|
"Delay cascading. 2 crew swaps needed."
|
|
)
|
|
SCENARIO_HUBS = ["EWR"]
|
|
|
|
FLIGHTS: list[FlightData] = [
|
|
FlightData(
|
|
flight_id="UA2180", origin="EWR", destination="LAX",
|
|
scheduled_departure=datetime(2026, 4, 11, 20, 0, tzinfo=timezone.utc),
|
|
actual_departure=None,
|
|
scheduled_arrival=datetime(2026, 4, 11, 23, 30, tzinfo=timezone.utc),
|
|
status=FlightStatus.DELAYED,
|
|
delay_minutes=90,
|
|
delay_cause=DelayCause.CREW,
|
|
aircraft_tail="N81201",
|
|
gate="C72",
|
|
crew_ids=["CR-3001", "CR-3002", "CR-3010", "CR-3011"],
|
|
passenger_count=210,
|
|
),
|
|
FlightData(
|
|
flight_id="UA2244", origin="EWR", destination="ORD",
|
|
scheduled_departure=datetime(2026, 4, 11, 20, 30, tzinfo=timezone.utc),
|
|
actual_departure=None,
|
|
scheduled_arrival=datetime(2026, 4, 11, 22, 0, tzinfo=timezone.utc),
|
|
status=FlightStatus.DELAYED,
|
|
delay_minutes=45,
|
|
delay_cause=DelayCause.LATE_AIRCRAFT,
|
|
aircraft_tail="N81202",
|
|
gate="C87",
|
|
crew_ids=["CR-3003", "CR-3004", "CR-3012"],
|
|
passenger_count=178,
|
|
),
|
|
FlightData(
|
|
flight_id="UA2310", origin="EWR", destination="SFO",
|
|
scheduled_departure=datetime(2026, 4, 11, 21, 0, tzinfo=timezone.utc),
|
|
scheduled_arrival=datetime(2026, 4, 12, 0, 15, tzinfo=timezone.utc),
|
|
status=FlightStatus.ON_TIME,
|
|
aircraft_tail="N81203",
|
|
gate="C90",
|
|
crew_ids=["CR-3005", "CR-3006"],
|
|
passenger_count=195,
|
|
),
|
|
]
|
|
|
|
CREW: list[CrewMember] = [
|
|
# UA2180 — captain at limit
|
|
CrewMember(crew_id="CR-3001", name="Capt. Mitchell", role=CrewRole.CAPTAIN,
|
|
duty_hours_elapsed=12.25, duty_hours_limit=14.0,
|
|
rest_hours_since_last=10.0, next_scheduled_flight="UA2180", base_hub="EWR"),
|
|
CrewMember(crew_id="CR-3002", name="FO Vasquez", role=CrewRole.FIRST_OFFICER,
|
|
duty_hours_elapsed=11.0, duty_hours_limit=14.0,
|
|
rest_hours_since_last=11.0, next_scheduled_flight="UA2180", base_hub="EWR"),
|
|
# UA2244
|
|
CrewMember(crew_id="CR-3003", name="Capt. Ali", role=CrewRole.CAPTAIN,
|
|
duty_hours_elapsed=8.0, duty_hours_limit=14.0,
|
|
rest_hours_since_last=14.0, next_scheduled_flight="UA2244", base_hub="EWR"),
|
|
CrewMember(crew_id="CR-3004", name="FO Johansson", role=CrewRole.FIRST_OFFICER,
|
|
duty_hours_elapsed=8.0, duty_hours_limit=14.0,
|
|
rest_hours_since_last=13.0, next_scheduled_flight="UA2244", base_hub="EWR"),
|
|
# UA2310
|
|
CrewMember(crew_id="CR-3005", name="Capt. Reed", role=CrewRole.CAPTAIN,
|
|
duty_hours_elapsed=4.0, duty_hours_limit=14.0,
|
|
rest_hours_since_last=20.0, next_scheduled_flight="UA2310", base_hub="EWR"),
|
|
CrewMember(crew_id="CR-3006", name="FO Torres", role=CrewRole.FIRST_OFFICER,
|
|
duty_hours_elapsed=4.0, duty_hours_limit=14.0,
|
|
rest_hours_since_last=18.0, next_scheduled_flight="UA2310", base_hub="EWR"),
|
|
# FAs
|
|
CrewMember(crew_id="CR-3010", name="FA Collins", role=CrewRole.FA,
|
|
duty_hours_elapsed=11.5, duty_hours_limit=14.0,
|
|
rest_hours_since_last=10.0, next_scheduled_flight="UA2180", base_hub="EWR"),
|
|
CrewMember(crew_id="CR-3011", name="FA Yamamoto", role=CrewRole.FA,
|
|
duty_hours_elapsed=11.5, duty_hours_limit=14.0,
|
|
rest_hours_since_last=10.0, next_scheduled_flight="UA2180", base_hub="EWR"),
|
|
CrewMember(crew_id="CR-3012", name="FA Petrov", role=CrewRole.FA,
|
|
duty_hours_elapsed=7.0, duty_hours_limit=14.0,
|
|
rest_hours_since_last=15.0, next_scheduled_flight="UA2244", base_hub="EWR"),
|
|
# Backup crew
|
|
CrewMember(crew_id="CR-8812", name="Capt. Foster", role=CrewRole.CAPTAIN,
|
|
duty_hours_elapsed=0.0, duty_hours_limit=14.0,
|
|
rest_hours_since_last=28.0, next_scheduled_flight=None, base_hub="EWR"),
|
|
CrewMember(crew_id="CR-8813", name="FO Chang", role=CrewRole.FIRST_OFFICER,
|
|
duty_hours_elapsed=0.0, duty_hours_limit=14.0,
|
|
rest_hours_since_last=24.0, next_scheduled_flight=None, base_hub="EWR"),
|
|
]
|
|
|
|
CREW_NOTES: dict[str, list[str]] = {
|
|
"UA2180": [
|
|
"Capt. Mitchell duty limit approaching — 1h 45min remaining.",
|
|
"If departure slips past 22:15 ET, mandatory crew swap per Part 117 §117.19.",
|
|
"Backup Capt. Foster (CR-8812) on standby at crew lounge, cleared and rested.",
|
|
"FO Vasquez also approaching limit but has buffer until 23:00.",
|
|
],
|
|
"UA2244": [
|
|
"Delay is cascading from late inbound aircraft, not crew-related.",
|
|
"Gate conflict resolved — moved to C87.",
|
|
],
|
|
}
|
|
|
|
MAINTENANCE: dict[str, list[MELItem]] = {}
|
|
REBOOKINGS: list[RebookingCase] = []
|
|
PASSENGERS: list[Passenger] = []
|