Vibrometer

Olympiad

Part 117 Crew Legality Audit

Ticket CREW-1184, from Marisol Okafor-Lind, Manager, Crew Scheduling, Bluestem Air

Our FAA principal operations inspector (POI) wants an audit of last week's flying against Part 117, built from what actually happened, not the roster: every pilot's duty periods and every limit that was broken. And before Monday's first departures I need to know which of next week's trips we can't legally start. We did the same audit by hand for the week of 12 October and the inspector accepted it; it's in data/reference_case/, so match its conventions. We want a function that we can run again every week.

I'm in schedule meetings most of the week. Ask me what you need, but I can answer a few questions, not dozens.

Bluestem Air is a fictional US regional airline. It flies under 14 CFR Part 121, and its flightcrew members are subject to 14 CFR Part 117 (Flightcrew Member Duty and Rest Requirements).

Deliverable

Write solve(files) in solution.mjs. files maps each path under data/ to its text contents, including the files in data/reference_case/. The function returns the audit of the week in data/ and the check of next week's first trips, described under Output. It must ignore everything under data/reference_case/.

data/reference_case/ holds the week of 12 to 18 October 2026 with the same layout as data/, apart from files that we didn't have that week, plus approved_audit.json. If you pass your function the files under data/reference_case/ (with that prefix replaced by data/), it must return approved_audit.json. Anything that Part 117 leaves open, such as how report and release times are set, how crew scheduling's entries apply and how one duty period is told apart from the next, follows the approved audit.

The graders run solve on other weeks with the same layout, generated with different crews, schedules and irregular operations. Those weeks have no data/reference_case/ folder.

Working on this challenge

  • Questions. Marisol knows what the audit covers, how Bluestem's crews are assigned and the arrangements behind the files, and much of that isn't written down in the folder. Ask her with vibrometer ask "your question". You have 7 questions, she answers only what you ask, and a vague question gets a question back.
  • Follow-up. Run vibrometer update from time to time. Anything new from Marisol arrives in your folder with a CHANGE.md. The graders always test the latest requirements.

Input files

  • data/roster/: the roster extracts (fixed-width) and next week's pairing extract.
  • data/ops/: the two operations exports of what was flown.
  • data/crew/: the crew list, the duty history before the week, crew scheduling's entries and other crew files.
  • data/ref/: stations and equipment. data/misc/: files that people sent along; not all of them matter.

Regulations

The eCFR text of 14 CFR Part 117 is the authority for every limit: Table A (117.11), Table B (117.13), reserve status (117.21), the cumulative limits (117.23) and rest (117.25), with the definitions in 117.3. Which parts the audit checks, and the conditions that held during the week, are Marisol's to tell you.

Output

{
  dutyPeriods: [{
    employee,               // string, emp_no as in crew.csv, e.g. "41233"
    start,                  // start of the duty period
    end,                    // release from duty
    fdpEnd,                 // end of the flight duty period, or null if the duty period has none
    segments,               // integer, flight segments in the sense of Table B
    flightMinutes,          // flight time in this duty period
    fdpMinutes,             // fdpEnd - start, or null
    fdpLimitMinutes,        // Table B limit, or null when there are no segments
    flightTimeLimitMinutes, // Table A limit, or null when there are no segments
    restBeforeMinutes,      // minutes from the previous release (this week or earlier) to start, or null if there is none
  }],
  violations: [{
    employee,       // string, as above
    rule,           // "117.11" | "117.13" | "117.23(b)(1)" | "117.23(c)(1)" | "117.25(b)" | "117.25(e)"
    dutyStart,      // start of the flight duty period that was checked
    limitMinutes,   // the limit, or for 117.25(b) and 117.25(e) the minimum required
    actualMinutes,  // the measured value
    excessMinutes,  // actualMinutes - limitMinutes; for 117.25(b) and 117.25(e), limitMinutes - actualMinutes
  }],
  summary: {
    pilotsChecked,  // number of distinct pilots with at least one duty period in the week
    dutyPeriods,    // number of entries in dutyPeriods
    byRule,         // { "117.11": n, "117.13": n, ... } with every rule code, including zeros
  },
  nextWeek: [{
    employee,           // string, as above
    pairing,            // pairing id in next week's extract, e.g. "B45777"
    report,             // planned report for the pilot's first duty day next week
    restBeforeMinutes,  // minutes from the pilot's last actual release to report, or null if there is none
    fdp168Minutes,      // FDP minutes in the 168 hours that end at the planned end of that FDP, including it
    flight672Minutes,   // flight time in the 672 hours that end at the same moment, including the planned block time
    issues,             // the rule codes above that this duty day would break, sorted; [] when it is legal
  }],
}
  • All instants are UTC strings in the form YYYY-MM-DDTHH:MMZ, for example 2026-10-26T11:35Z.
  • All durations are integer minutes.
  • Each violation is a separate entry, so one flight duty period can appear under several rules.
  • nextWeek covers every pilot who is listed on a leg of next week's pairing extract, as a crew member or as a deadheading crew member. The pilot's first duty day is the earliest duty day (pairing and duty-day number) in which they are listed. Its planned times come from the scheduled times in the extract, with the same report and release conventions as the audit. Planned block time is STA minus STD of the legs that the pilot operates. fdp168Minutes and flight672Minutes are null when that duty day has no flight segment for the pilot, and then issues is [].
  • Sort dutyPeriods by start, then employee. Sort violations by dutyStart, then employee, then rule. Sort nextWeek by report, then employee. Use plain string comparison throughout.

The solution has to be one file that imports nothing except node: built-ins. It gets no file system or network access, and every input arrives through files.

Start this challenge

First, add Vibrometer to Claude Code

You only do this once. In Claude Code, type these two commands:

/plugin marketplace add usesieve/vibrometer-plugin
/plugin install vibrometer@vibrometer

Then read the ticket and start the clock. In Claude Code, from an empty folder, get the ticket (the clock doesn’t start):

/vibrometer:challenge crew-legality

When you’re ready to lead the work:

/vibrometer:start

When you’re done:

/vibrometer:submit

Fastest

AI alone, one prompt: 10/30 tests in 10 min.

No entries yet.