init commit

This commit is contained in:
2026-04-12 07:19:48 -03:00
commit 9dbf89da02
111 changed files with 14925 additions and 0 deletions

View File

View File

@@ -0,0 +1,123 @@
"""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] = []

View File

@@ -0,0 +1,117 @@
"""Scenario: SFO Maintenance Delay — MEL issue cascading to 2 flights.
Aircraft N82301 has APU MEL, delay cascading. Tests FCE maintenance-caused
delay explanation and Handover MEL flag section.
"""
from datetime import datetime, timezone
from mcp_servers.data.models import (
CrewMember,
CrewRole,
DelayCause,
FlightData,
FlightStatus,
MELItem,
MPStatus,
Passenger,
RebookingCase,
)
SCENARIO_ID = "maintenance_delay_sfo"
SCENARIO_NAME = "SFO MEL Issue"
SCENARIO_DESCRIPTION = (
"Aircraft N82301 APU inoperative (MEL). Delay cascading to 2 flights. "
"Route restriction if divert needed."
)
SCENARIO_HUBS = ["SFO"]
FLIGHTS: list[FlightData] = [
FlightData(
flight_id="UA712", origin="SFO", destination="EWR",
scheduled_departure=datetime(2026, 4, 11, 19, 0, tzinfo=timezone.utc),
actual_departure=None,
scheduled_arrival=datetime(2026, 4, 12, 3, 30, tzinfo=timezone.utc),
status=FlightStatus.DELAYED,
delay_minutes=65,
delay_cause=DelayCause.MAINTENANCE,
aircraft_tail="N82301",
gate="G4",
crew_ids=["CR-4001", "CR-4002", "CR-4010"],
passenger_count=198,
),
FlightData(
flight_id="UA724", origin="SFO", destination="DEN",
scheduled_departure=datetime(2026, 4, 11, 20, 30, tzinfo=timezone.utc),
scheduled_arrival=datetime(2026, 4, 11, 23, 45, tzinfo=timezone.utc),
status=FlightStatus.DELAYED,
delay_minutes=30,
delay_cause=DelayCause.LATE_AIRCRAFT,
aircraft_tail="N82302",
gate="G8",
crew_ids=["CR-4003", "CR-4004"],
passenger_count=165,
),
FlightData(
flight_id="UA760", origin="SFO", destination="LAX",
scheduled_departure=datetime(2026, 4, 11, 18, 30, tzinfo=timezone.utc),
scheduled_arrival=datetime(2026, 4, 11, 19, 45, tzinfo=timezone.utc),
status=FlightStatus.ON_TIME,
aircraft_tail="N82303",
gate="G12",
crew_ids=["CR-4005", "CR-4006"],
passenger_count=140,
),
]
CREW: list[CrewMember] = [
CrewMember(crew_id="CR-4001", name="Capt. Novak", role=CrewRole.CAPTAIN,
duty_hours_elapsed=6.0, duty_hours_limit=14.0,
rest_hours_since_last=16.0, next_scheduled_flight="UA712", base_hub="SFO"),
CrewMember(crew_id="CR-4002", name="FO Agrawal", role=CrewRole.FIRST_OFFICER,
duty_hours_elapsed=6.0, duty_hours_limit=14.0,
rest_hours_since_last=15.0, next_scheduled_flight="UA712", base_hub="SFO"),
CrewMember(crew_id="CR-4003", name="Capt. Svensson", role=CrewRole.CAPTAIN,
duty_hours_elapsed=5.0, duty_hours_limit=14.0,
rest_hours_since_last=18.0, next_scheduled_flight="UA724", base_hub="SFO"),
CrewMember(crew_id="CR-4004", name="FO Rivera", role=CrewRole.FIRST_OFFICER,
duty_hours_elapsed=5.0, duty_hours_limit=14.0,
rest_hours_since_last=17.0, next_scheduled_flight="UA724", base_hub="SFO"),
CrewMember(crew_id="CR-4005", name="Capt. Wallace", role=CrewRole.CAPTAIN,
duty_hours_elapsed=3.0, duty_hours_limit=14.0,
rest_hours_since_last=22.0, next_scheduled_flight="UA760", base_hub="SFO"),
CrewMember(crew_id="CR-4006", name="FO Zhao", role=CrewRole.FIRST_OFFICER,
duty_hours_elapsed=3.0, duty_hours_limit=14.0,
rest_hours_since_last=20.0, next_scheduled_flight="UA760", base_hub="SFO"),
CrewMember(crew_id="CR-4010", name="FA Douglas", role=CrewRole.FA,
duty_hours_elapsed=5.5, duty_hours_limit=14.0,
rest_hours_since_last=16.0, next_scheduled_flight="UA712", base_hub="SFO"),
]
CREW_NOTES: dict[str, list[str]] = {
"UA712": [
"MEL item #47-3: APU inoperative on N82301.",
"Maintenance team inspecting — estimated release in 45 min.",
"APU MEL restricts routing to airports with ground power only.",
"Current SFO→EWR route unaffected, but flag if divert to BDL or HPN needed.",
],
"UA724": [
"Delay cascading from UA712 — shared gate G8 not available until UA712 pushes.",
],
}
MAINTENANCE: dict[str, list[MELItem]] = {
"N82301": [
MELItem(
mel_id="MEL-SFO-473",
aircraft_tail="N82301",
system="APU",
description="Auxiliary Power Unit inoperative. Aircraft requires external ground power for engine start and gate operations.",
restriction="Routing restricted to airports with ground power availability. Cannot divert to airports without ground power units (e.g., BDL, HPN).",
expires=datetime(2026, 4, 18, 0, 0, tzinfo=timezone.utc),
),
],
}
REBOOKINGS: list[RebookingCase] = []
PASSENGERS: list[Passenger] = []

View File

@@ -0,0 +1,85 @@
"""Scenario manager — loads and switches between operational scenarios."""
from importlib import import_module
from typing import Any
SCENARIO_MODULES = {
"normal_ops": "mcp_servers.data.scenarios.normal_ops",
"weather_disruption_ord": "mcp_servers.data.scenarios.weather_disruption_ord",
"maintenance_delay_sfo": "mcp_servers.data.scenarios.maintenance_delay_sfo",
"crew_swap_ewr": "mcp_servers.data.scenarios.crew_swap_ewr",
}
class ScenarioManager:
"""Manages the active scenario. Singleton — all MCP servers share one instance."""
def __init__(self) -> None:
self._active_id: str = "weather_disruption_ord"
self._cache: dict[str, Any] = {}
@property
def active_id(self) -> str:
return self._active_id
def set_active(self, scenario_id: str) -> dict:
if scenario_id not in SCENARIO_MODULES:
raise ValueError(
f"Unknown scenario: {scenario_id}. "
f"Available: {', '.join(SCENARIO_MODULES.keys())}"
)
self._active_id = scenario_id
return self.get_metadata()
def get_metadata(self, scenario_id: str | None = None) -> dict:
mod = self._load(scenario_id or self._active_id)
return {
"scenario_id": mod.SCENARIO_ID,
"name": mod.SCENARIO_NAME,
"description": mod.SCENARIO_DESCRIPTION,
"hubs": mod.SCENARIO_HUBS,
"flight_count": len(mod.FLIGHTS),
"disrupted_flights": sum(
1 for f in mod.FLIGHTS if f.status != "ON_TIME"
),
}
def list_scenarios(self) -> list[dict]:
return [self.get_metadata(sid) for sid in SCENARIO_MODULES]
def _load(self, scenario_id: str) -> Any:
if scenario_id not in self._cache:
self._cache[scenario_id] = import_module(SCENARIO_MODULES[scenario_id])
return self._cache[scenario_id]
@property
def _module(self) -> Any:
return self._load(self._active_id)
@property
def flights(self):
return self._module.FLIGHTS
@property
def crew(self):
return self._module.CREW
@property
def crew_notes(self) -> dict[str, list[str]]:
return self._module.CREW_NOTES
@property
def maintenance(self):
return self._module.MAINTENANCE
@property
def rebookings(self):
return self._module.REBOOKINGS
@property
def passengers(self):
return self._module.PASSENGERS
# Singleton
scenario_manager = ScenarioManager()

View File

@@ -0,0 +1,72 @@
"""Scenario: Normal Operations — all flights on time, clear weather, full crew.
Baseline scenario. Agents should produce minimal/calm output.
"""
from datetime import datetime, timezone
from mcp_servers.data.models import (
CrewMember,
CrewRole,
FlightData,
FlightStatus,
MPStatus,
Passenger,
RebookingCase,
MELItem,
)
SCENARIO_ID = "normal_ops"
SCENARIO_NAME = "Normal Operations"
SCENARIO_DESCRIPTION = "All flights on time at ORD. Clear weather. No disruptions."
SCENARIO_HUBS = ["ORD"]
FLIGHTS: list[FlightData] = [
FlightData(
flight_id="UA1440", origin="ORD", destination="SFO",
scheduled_departure=datetime(2026, 4, 11, 18, 0, tzinfo=timezone.utc),
scheduled_arrival=datetime(2026, 4, 11, 20, 30, tzinfo=timezone.utc),
status=FlightStatus.ON_TIME, aircraft_tail="N79001", gate="H10",
crew_ids=["CR-2001", "CR-2002"], passenger_count=175,
),
FlightData(
flight_id="UA1552", origin="ORD", destination="EWR",
scheduled_departure=datetime(2026, 4, 11, 18, 30, tzinfo=timezone.utc),
scheduled_arrival=datetime(2026, 4, 11, 21, 45, tzinfo=timezone.utc),
status=FlightStatus.ON_TIME, aircraft_tail="N79002", gate="B12",
crew_ids=["CR-2003", "CR-2004"], passenger_count=190,
),
FlightData(
flight_id="UA1678", origin="ORD", destination="DEN",
scheduled_departure=datetime(2026, 4, 11, 19, 0, tzinfo=timezone.utc),
scheduled_arrival=datetime(2026, 4, 11, 20, 30, tzinfo=timezone.utc),
status=FlightStatus.ON_TIME, aircraft_tail="N79003", gate="C8",
crew_ids=["CR-2005", "CR-2006"], passenger_count=160,
),
]
CREW: list[CrewMember] = [
CrewMember(crew_id="CR-2001", name="Capt. Hayes", role=CrewRole.CAPTAIN,
duty_hours_elapsed=4.0, duty_hours_limit=14.0,
rest_hours_since_last=18.0, next_scheduled_flight="UA1440", base_hub="ORD"),
CrewMember(crew_id="CR-2002", name="FO Park", role=CrewRole.FIRST_OFFICER,
duty_hours_elapsed=4.0, duty_hours_limit=14.0,
rest_hours_since_last=16.0, next_scheduled_flight="UA1440", base_hub="ORD"),
CrewMember(crew_id="CR-2003", name="Capt. Lewis", role=CrewRole.CAPTAIN,
duty_hours_elapsed=5.0, duty_hours_limit=14.0,
rest_hours_since_last=15.0, next_scheduled_flight="UA1552", base_hub="ORD"),
CrewMember(crew_id="CR-2004", name="FO Sharma", role=CrewRole.FIRST_OFFICER,
duty_hours_elapsed=5.0, duty_hours_limit=14.0,
rest_hours_since_last=14.0, next_scheduled_flight="UA1552", base_hub="ORD"),
CrewMember(crew_id="CR-2005", name="Capt. Brown", role=CrewRole.CAPTAIN,
duty_hours_elapsed=3.0, duty_hours_limit=14.0,
rest_hours_since_last=20.0, next_scheduled_flight="UA1678", base_hub="ORD"),
CrewMember(crew_id="CR-2006", name="FO Nguyen", role=CrewRole.FIRST_OFFICER,
duty_hours_elapsed=3.0, duty_hours_limit=14.0,
rest_hours_since_last=19.0, next_scheduled_flight="UA1678", base_hub="ORD"),
]
CREW_NOTES: dict[str, list[str]] = {}
MAINTENANCE: dict[str, list[MELItem]] = {}
REBOOKINGS: list[RebookingCase] = []
PASSENGERS: list[Passenger] = []

View File

@@ -0,0 +1,281 @@
"""Scenario: ORD Thunderstorms — active disruption at Chicago O'Hare.
Thunderstorm line causing GDP, 4 flights delayed, 1 cancelled.
Tests FCE multi-flight notifications and Handover weather risk section.
"""
from datetime import datetime, timezone
from mcp_servers.data.models import (
CrewMember,
CrewRole,
DelayCause,
FlightData,
FlightStatus,
MELItem,
MPStatus,
Passenger,
RebookingCase,
)
SCENARIO_ID = "weather_disruption_ord"
SCENARIO_NAME = "ORD Thunderstorms"
SCENARIO_DESCRIPTION = (
"Active thunderstorm line at ORD. GDP in effect. "
"4 delays, 1 cancellation. 47 passengers need rebooking."
)
SCENARIO_HUBS = ["ORD"]
# --- Flights ---
FLIGHTS: list[FlightData] = [
# Delayed flights
FlightData(
flight_id="UA432",
origin="ORD", destination="SFO",
scheduled_departure=datetime(2026, 4, 11, 17, 45, tzinfo=timezone.utc),
actual_departure=None,
scheduled_arrival=datetime(2026, 4, 11, 20, 15, tzinfo=timezone.utc),
actual_arrival=None,
status=FlightStatus.DELAYED,
delay_minutes=55,
delay_cause=DelayCause.WEATHER,
aircraft_tail="N78501",
gate="H14",
inbound_flight="UA219",
crew_ids=["CR-1001", "CR-1002", "CR-1010", "CR-1011"],
passenger_count=186,
),
FlightData(
flight_id="UA881",
origin="ORD", destination="LAX",
scheduled_departure=datetime(2026, 4, 11, 18, 30, tzinfo=timezone.utc),
actual_departure=None,
scheduled_arrival=datetime(2026, 4, 11, 21, 0, tzinfo=timezone.utc),
actual_arrival=None,
status=FlightStatus.DELAYED,
delay_minutes=40,
delay_cause=DelayCause.WEATHER,
aircraft_tail="N78502",
gate="H22",
crew_ids=["CR-1003", "CR-1004", "CR-1012", "CR-1013"],
passenger_count=204,
),
FlightData(
flight_id="UA233",
origin="ORD", destination="DEN",
scheduled_departure=datetime(2026, 4, 11, 18, 0, tzinfo=timezone.utc),
actual_departure=None,
scheduled_arrival=datetime(2026, 4, 11, 19, 45, tzinfo=timezone.utc),
actual_arrival=None,
status=FlightStatus.DELAYED,
delay_minutes=70,
delay_cause=DelayCause.WEATHER,
aircraft_tail="N78503",
gate="C12",
crew_ids=["CR-1005", "CR-1006", "CR-1014"],
passenger_count=152,
),
FlightData(
flight_id="UA094",
origin="ORD", destination="EWR",
scheduled_departure=datetime(2026, 4, 11, 17, 15, tzinfo=timezone.utc),
actual_departure=None,
scheduled_arrival=datetime(2026, 4, 11, 20, 30, tzinfo=timezone.utc),
actual_arrival=None,
status=FlightStatus.DELAYED,
delay_minutes=35,
delay_cause=DelayCause.WEATHER,
aircraft_tail="N78504",
gate="B8",
crew_ids=["CR-1007", "CR-1008", "CR-1015"],
passenger_count=178,
),
# Cancelled flight
FlightData(
flight_id="UA517",
origin="ORD", destination="IAH",
scheduled_departure=datetime(2026, 4, 11, 19, 0, tzinfo=timezone.utc),
actual_departure=None,
scheduled_arrival=datetime(2026, 4, 11, 21, 30, tzinfo=timezone.utc),
actual_arrival=None,
status=FlightStatus.CANCELLED,
delay_minutes=0,
delay_cause=DelayCause.WEATHER,
aircraft_tail="N78505",
gate="C18",
crew_ids=["CR-1009", "CR-1016"],
passenger_count=47,
),
# On-time flights (normal ops happening alongside disruption)
FlightData(
flight_id="UA1220",
origin="ORD", destination="IAD",
scheduled_departure=datetime(2026, 4, 11, 20, 30, tzinfo=timezone.utc),
actual_departure=None,
scheduled_arrival=datetime(2026, 4, 11, 23, 15, tzinfo=timezone.utc),
actual_arrival=None,
status=FlightStatus.ON_TIME,
delay_minutes=0,
delay_cause=None,
aircraft_tail="N78506",
gate="B15",
crew_ids=["CR-1017", "CR-1018"],
passenger_count=145,
),
FlightData(
flight_id="UA788",
origin="ORD", destination="SFO",
scheduled_departure=datetime(2026, 4, 11, 21, 0, tzinfo=timezone.utc),
actual_departure=None,
scheduled_arrival=datetime(2026, 4, 11, 23, 30, tzinfo=timezone.utc),
actual_arrival=None,
status=FlightStatus.ON_TIME,
delay_minutes=0,
delay_cause=None,
aircraft_tail="N78507",
gate="H18",
crew_ids=["CR-1019", "CR-1020"],
passenger_count=192,
),
]
# --- Crew ---
CREW: list[CrewMember] = [
# UA432 crew
CrewMember(crew_id="CR-1001", name="Capt. Rodriguez", role=CrewRole.CAPTAIN,
duty_hours_elapsed=10.5, duty_hours_limit=14.0,
rest_hours_since_last=12.0, next_scheduled_flight="UA432", base_hub="ORD"),
CrewMember(crew_id="CR-1002", name="FO Chen", role=CrewRole.FIRST_OFFICER,
duty_hours_elapsed=10.5, duty_hours_limit=14.0,
rest_hours_since_last=11.0, next_scheduled_flight="UA432", base_hub="ORD"),
# UA881 crew — captain approaching duty limit
CrewMember(crew_id="CR-1003", name="Capt. Williams", role=CrewRole.CAPTAIN,
duty_hours_elapsed=12.25, duty_hours_limit=14.0,
rest_hours_since_last=10.0, next_scheduled_flight="UA881", base_hub="ORD"),
CrewMember(crew_id="CR-1004", name="FO Patel", role=CrewRole.FIRST_OFFICER,
duty_hours_elapsed=9.0, duty_hours_limit=14.0,
rest_hours_since_last=14.0, next_scheduled_flight="UA881", base_hub="ORD"),
# UA233 crew
CrewMember(crew_id="CR-1005", name="Capt. Johnson", role=CrewRole.CAPTAIN,
duty_hours_elapsed=8.0, duty_hours_limit=14.0,
rest_hours_since_last=16.0, next_scheduled_flight="UA233", base_hub="ORD"),
CrewMember(crew_id="CR-1006", name="FO Kim", role=CrewRole.FIRST_OFFICER,
duty_hours_elapsed=7.5, duty_hours_limit=14.0,
rest_hours_since_last=15.0, next_scheduled_flight="UA233", base_hub="ORD"),
# UA094 crew
CrewMember(crew_id="CR-1007", name="Capt. Davis", role=CrewRole.CAPTAIN,
duty_hours_elapsed=6.0, duty_hours_limit=14.0,
rest_hours_since_last=18.0, next_scheduled_flight="UA094", base_hub="ORD"),
CrewMember(crew_id="CR-1008", name="FO Martinez", role=CrewRole.FIRST_OFFICER,
duty_hours_elapsed=6.0, duty_hours_limit=14.0,
rest_hours_since_last=17.0, next_scheduled_flight="UA094", base_hub="ORD"),
# UA517 crew (cancelled flight — available for reassignment)
CrewMember(crew_id="CR-1009", name="Capt. Thompson", role=CrewRole.CAPTAIN,
duty_hours_elapsed=4.0, duty_hours_limit=14.0,
rest_hours_since_last=20.0, next_scheduled_flight=None, base_hub="ORD"),
# Flight attendants
CrewMember(crew_id="CR-1010", name="FA Brooks", role=CrewRole.FA,
duty_hours_elapsed=10.0, duty_hours_limit=14.0,
rest_hours_since_last=12.0, next_scheduled_flight="UA432", base_hub="ORD"),
CrewMember(crew_id="CR-1011", name="FA Lee", role=CrewRole.FA,
duty_hours_elapsed=10.0, duty_hours_limit=14.0,
rest_hours_since_last=13.0, next_scheduled_flight="UA432", base_hub="ORD"),
CrewMember(crew_id="CR-1012", name="FA Garcia", role=CrewRole.FA,
duty_hours_elapsed=11.5, duty_hours_limit=14.0,
rest_hours_since_last=10.0, next_scheduled_flight="UA881", base_hub="ORD"),
# Backup crew
CrewMember(crew_id="CR-4421", name="Capt. Okafor", role=CrewRole.CAPTAIN,
duty_hours_elapsed=0.0, duty_hours_limit=14.0,
rest_hours_since_last=24.0, next_scheduled_flight=None, base_hub="ORD"),
]
# --- Crew Notes ---
CREW_NOTES: dict[str, list[str]] = {
"UA432": [
"Ground stop at ORD — thunderstorm line moving NE across field.",
"Inbound aircraft N78501 on ground, boarding paused at gate H14.",
"Fresh crew on board, catering complete. Ready to board on release.",
"Gate hold — no gate change expected per ops.",
],
"UA881": [
"Capt. Williams approaching duty limit — monitor closely.",
"If departure slips past 22:15 CT, mandatory crew swap required.",
"Backup crew CR-4421 (Capt. Okafor) on standby, cleared and rested.",
],
"UA233": [
"Extended delay due to weather at ORD and congestion at DEN.",
"8 connecting passengers with tight connections at DEN — rebooking may be needed.",
],
"UA094": [
"Moderate delay. EWR reporting clear conditions, delay is ORD-side only.",
],
"UA517": [
"CANCELLED — thunderstorm forecast through departure window.",
"47 passengers need rebooking. 8 Global Services pax — priority handling.",
"Rebooking options loaded in system — supervisor approval pending.",
],
}
# --- Maintenance ---
MAINTENANCE: dict[str, list[MELItem]] = {
"N78501": [
MELItem(
mel_id="MEL-ORD-001",
aircraft_tail="N78501",
system="WEATHER_RADAR",
description="Weather radar intermittent — functions normally after reset cycle.",
restriction=None,
expires=datetime(2026, 4, 15, 0, 0, tzinfo=timezone.utc),
),
],
}
# --- Passengers needing rebooking (from cancelled UA517) ---
REBOOKINGS: list[RebookingCase] = [
RebookingCase(pax_id="PAX-00341", name="J. Morrison",
original_flight="UA517", mileage_plus_status=MPStatus.GLOBAL_SERVICES,
destination="IAH", next_available="UA519", urgency="HIGH"),
RebookingCase(pax_id="PAX-00342", name="S. Nakamura",
original_flight="UA517", mileage_plus_status=MPStatus.GLOBAL_SERVICES,
destination="IAH", next_available="UA519", urgency="HIGH"),
RebookingCase(pax_id="PAX-00355", name="R. Okonkwo",
original_flight="UA517", mileage_plus_status=MPStatus.K1,
destination="IAH", next_available="UA519", urgency="HIGH"),
RebookingCase(pax_id="PAX-00360", name="M. Fernandez",
original_flight="UA517", mileage_plus_status=MPStatus.PLATINUM,
destination="IAH", next_available=None, urgency="MEDIUM"),
RebookingCase(pax_id="PAX-00371", name="K. Singh",
original_flight="UA517", mileage_plus_status=MPStatus.GOLD,
destination="IAH", next_available=None, urgency="MEDIUM"),
RebookingCase(pax_id="PAX-00380", name="L. Anderson",
original_flight="UA517", mileage_plus_status=MPStatus.GENERAL,
destination="IAH", next_available=None, urgency="LOW"),
]
# --- Passengers on disrupted flights (sample) ---
PASSENGERS: list[Passenger] = [
# UA432 passengers
Passenger(pax_id="PAX-10001", name="A. Kowalski",
mileage_plus_status=MPStatus.GLOBAL_SERVICES, flight_id="UA432",
destination="SFO", connection_flight="UA1892",
connection_deadline=datetime(2026, 4, 11, 21, 30, tzinfo=timezone.utc)),
Passenger(pax_id="PAX-10002", name="B. Tanaka",
mileage_plus_status=MPStatus.K1, flight_id="UA432",
destination="SFO"),
Passenger(pax_id="PAX-10003", name="C. Dubois",
mileage_plus_status=MPStatus.GENERAL, flight_id="UA432",
destination="SFO", special_needs=["WCHR"]),
# UA517 passengers (cancelled)
Passenger(pax_id="PAX-00341", name="J. Morrison",
mileage_plus_status=MPStatus.GLOBAL_SERVICES, flight_id="UA517",
destination="IAH"),
Passenger(pax_id="PAX-00342", name="S. Nakamura",
mileage_plus_status=MPStatus.GLOBAL_SERVICES, flight_id="UA517",
destination="IAH"),
]