Skip to content
Choose your marketSelected market: United States

Deloitte Virtual Internship / Task 04

An original Ape Intern practical · Task 04

Service performance disparity review

Control for service mix and sample size before setting hub review priorities.

Start with the completed outputs, then use the materials to deliver your own work.

Read complete output first

Materials

learner/checkpoints/order-review.csv Read the full fileDownload file
order_idhubserviceroutecreated_atdue_atcohortlate_minutesoverdue_minutes
O0001HarbourstandardR112026-09-01T06:00:00Z2026-09-02T06:00:00Zcancelled00
O0002HarbourstandardR122026-09-02T07:00:00Z2026-09-03T07:00:00Zdelivered_late500
O0003HarbourstandardR112026-09-03T08:00:00Z2026-09-04T08:00:00Zon_time00
O0004HarbourstandardR122026-09-04T09:00:00Z2026-09-05T09:00:00Zon_time00
O0005HarbourstandardR112026-09-05T10:00:00Z2026-09-06T10:00:00Zdelivered_late500
O0006HarbourstandardR122026-09-06T11:00:00Z2026-09-07T11:00:00Zon_time00
O0007HarbourstandardR112026-09-07T12:00:00Z2026-09-08T12:00:00Zon_time00
O0008HarbourstandardR122026-09-08T13:00:00Z2026-09-09T13:00:00Zdelivered_late500
O0009HarbourstandardR112026-09-09T06:00:00Z2026-09-10T06:00:00Zon_time00
O0010HarbourstandardR122026-09-10T07:00:00Z2026-09-11T07:00:00Zon_time00
O0011HarbourstandardR112026-09-11T08:00:00Z2026-09-12T08:00:00Zdelivered_late500
O0012HarbourstandardR122026-09-12T09:00:00Z2026-09-13T09:00:00Zon_time00
O0013HarbourstandardR112026-09-13T10:00:00Z2026-09-14T10:00:00Zon_time00
O0014HarbourstandardR122026-09-01T11:00:00Z2026-09-02T11:00:00Zdelivered_late500
O0015HarbourstandardR112026-09-02T12:00:00Z2026-09-03T12:00:00Zon_time00
O0016HarbourstandardR122026-09-03T13:00:00Z2026-09-04T13:00:00Zon_time00
O0017HarbourstandardR112026-09-04T06:00:00Z2026-09-05T06:00:00Zdelivered_late500
O0018HarbourstandardR122026-09-05T07:00:00Z2026-09-06T07:00:00Zoverdue_open012540
O0019HarbourstandardR112026-09-06T08:00:00Z2026-09-07T08:00:00Zon_time00
O0020HarbourstandardR122026-09-07T09:00:00Z2026-09-08T09:00:00Zdelivered_late500
O0021HarbourstandardR112026-09-08T10:00:00Z2026-09-09T10:00:00Zon_time00
O0022HarbourstandardR122026-09-09T11:00:00Z2026-09-10T11:00:00Zon_time00
O0023HarbourstandardR112026-09-10T12:00:00Z2026-09-11T12:00:00Zdelivered_late500
O0024HarbourstandardR122026-09-11T13:00:00Z2026-09-12T13:00:00Zon_time00
O0025HarbourstandardR112026-09-12T06:00:00Z2026-09-13T06:00:00Zon_time00
O0026HarbourstandardR122026-09-13T07:00:00Z2026-09-14T07:00:00Zdelivered_late500
O0027HarbourstandardR112026-09-01T08:00:00Z2026-09-02T08:00:00Zon_time00
O0028HarbourstandardR122026-09-02T09:00:00Z2026-09-03T09:00:00Zon_time00
O0029HarbourstandardR112026-09-03T10:00:00Z2026-09-04T10:00:00Zdelivered_late500
O0030HarbourstandardR122026-09-04T11:00:00Z2026-09-05T11:00:00Zcancelled00
O0031HarbourstandardR112026-09-05T12:00:00Z2026-09-06T12:00:00Zon_time00
O0032HarbourstandardR122026-09-06T13:00:00Z2026-09-07T13:00:00Zdelivered_late500
O0033HarbourstandardR112026-09-07T06:00:00Z2026-09-08T06:00:00Zon_time00
O0034HarbourstandardR122026-09-08T07:00:00Z2026-09-09T07:00:00Zon_time00
O0035HarbourstandardR112026-09-09T08:00:00Z2026-09-10T08:00:00Zoverdue_open06720
O0036HarbourstandardR122026-09-10T09:00:00Z2026-09-11T09:00:00Zon_time00
O0037HarbourstandardR112026-09-11T10:00:00Z2026-09-12T10:00:00Zon_time00
O0038HarbourstandardR122026-09-12T11:00:00Z2026-09-13T11:00:00Zdelivered_late500
O0039HarbourstandardR112026-09-13T12:00:00Z2026-09-14T12:00:00Zon_time00
O0040HarbourstandardR122026-09-14T21:00:00Z2026-09-15T21:00:00Znot_mature00
O0041HarbourexpressR112026-09-01T06:00:00Z2026-09-01T14:00:00Zcancelled00
O0042HarbourexpressR122026-09-02T07:00:00Z2026-09-02T15:00:00Zdelivered_late500
O0043HarbourexpressR112026-09-03T08:00:00Z2026-09-03T16:00:00Zdelivered_late500
O0044HarbourexpressR122026-09-04T09:00:00Z2026-09-04T17:00:00Zdelivered_late500
O0045HarbourexpressR112026-09-05T10:00:00Z2026-09-05T18:00:00Zdelivered_late500
O0046HarbourexpressR122026-09-06T11:00:00Z2026-09-06T19:00:00Zdelivered_late500
O0047HarbourexpressR112026-09-07T12:00:00Z2026-09-07T20:00:00Zdelivered_late500
O0048HarbourexpressR122026-09-08T13:00:00Z2026-09-08T21:00:00Zdelivered_late500
O0049HarbourexpressR112026-09-09T06:00:00Z2026-09-09T14:00:00Zdelivered_late500
O0050HarbourexpressR122026-09-10T07:00:00Z2026-09-10T15:00:00Zdelivered_late500
O0051HarbourexpressR112026-09-11T08:00:00Z2026-09-11T16:00:00Zdelivered_late500
O0052HarbourexpressR122026-09-12T09:00:00Z2026-09-12T17:00:00Zdelivered_late500
O0053HarbourexpressR112026-09-13T10:00:00Z2026-09-13T18:00:00Zdelivered_late500
O0054HarbourexpressR122026-09-01T11:00:00Z2026-09-01T19:00:00Zdelivered_late500
O0055HarbourexpressR112026-09-02T12:00:00Z2026-09-02T20:00:00Zdelivered_late500
O0056HarbourexpressR122026-09-03T13:00:00Z2026-09-03T21:00:00Zdelivered_late500
O0057HarbourexpressR112026-09-04T06:00:00Z2026-09-04T14:00:00Zdelivered_late500
O0058HarbourexpressR122026-09-05T07:00:00Z2026-09-05T15:00:00Zoverdue_open013500
O0059HarbourexpressR112026-09-06T08:00:00Z2026-09-06T16:00:00Zdelivered_late500
O0060HarbourexpressR122026-09-14T21:00:00Z2026-09-15T05:00:00Znot_mature00
O0061EastgatestandardR212026-09-01T06:00:00Z2026-09-02T06:00:00Zcancelled00
O0062EastgatestandardR222026-09-02T07:00:00Z2026-09-03T07:00:00Zdelivered_late700
O0063EastgatestandardR212026-09-03T08:00:00Z2026-09-04T08:00:00Zon_time00
O0064EastgatestandardR222026-09-04T09:00:00Z2026-09-05T09:00:00Zon_time00
O0065EastgatestandardR212026-09-05T10:00:00Z2026-09-06T10:00:00Zon_time00
O0066EastgatestandardR222026-09-06T11:00:00Z2026-09-07T11:00:00Zdelivered_late700
O0067EastgatestandardR212026-09-07T12:00:00Z2026-09-08T12:00:00Zon_time00
O0068EastgatestandardR222026-09-08T13:00:00Z2026-09-09T13:00:00Zon_time00
O0069EastgatestandardR212026-09-09T06:00:00Z2026-09-10T06:00:00Zon_time00
O0070EastgatestandardR222026-09-10T07:00:00Z2026-09-11T07:00:00Zdelivered_late700
O0071EastgatestandardR212026-09-11T08:00:00Z2026-09-12T08:00:00Zon_time00
O0072EastgatestandardR222026-09-12T09:00:00Z2026-09-13T09:00:00Zon_time00
O0073EastgatestandardR212026-09-13T10:00:00Z2026-09-14T10:00:00Zon_time00
O0074EastgatestandardR222026-09-01T11:00:00Z2026-09-02T11:00:00Zdelivered_late700
O0075EastgatestandardR212026-09-02T12:00:00Z2026-09-03T12:00:00Zon_time00
O0076EastgatestandardR222026-09-03T13:00:00Z2026-09-04T13:00:00Zon_time00
O0077EastgatestandardR212026-09-04T06:00:00Z2026-09-05T06:00:00Zon_time00
O0078EastgatestandardR222026-09-05T07:00:00Z2026-09-06T07:00:00Zoverdue_open012540
O0079EastgatestandardR212026-09-06T08:00:00Z2026-09-07T08:00:00Zon_time00
O0080EastgatestandardR222026-09-14T21:00:00Z2026-09-15T21:00:00Znot_mature00
O0081EastgateexpressR212026-09-01T06:00:00Z2026-09-01T14:00:00Zcancelled00
O0082EastgateexpressR222026-09-02T07:00:00Z2026-09-02T15:00:00Zdelivered_late700
O0083EastgateexpressR212026-09-03T08:00:00Z2026-09-03T16:00:00Zon_time00
O0084EastgateexpressR222026-09-04T09:00:00Z2026-09-04T17:00:00Zdelivered_late700
O0085EastgateexpressR212026-09-05T10:00:00Z2026-09-05T18:00:00Zdelivered_late700
O0086EastgateexpressR222026-09-06T11:00:00Z2026-09-06T19:00:00Zon_time00
O0087EastgateexpressR212026-09-07T12:00:00Z2026-09-07T20:00:00Zdelivered_late700
O0088EastgateexpressR222026-09-08T13:00:00Z2026-09-08T21:00:00Zdelivered_late700
O0089EastgateexpressR212026-09-09T06:00:00Z2026-09-09T14:00:00Zon_time00
O0090EastgateexpressR222026-09-10T07:00:00Z2026-09-10T15:00:00Zdelivered_late700
O0091EastgateexpressR212026-09-11T08:00:00Z2026-09-11T16:00:00Zdelivered_late700
O0092EastgateexpressR222026-09-12T09:00:00Z2026-09-12T17:00:00Zon_time00
O0093EastgateexpressR212026-09-13T10:00:00Z2026-09-13T18:00:00Zdelivered_late700
O0094EastgateexpressR222026-09-01T11:00:00Z2026-09-01T19:00:00Zdelivered_late700
O0095EastgateexpressR212026-09-02T12:00:00Z2026-09-02T20:00:00Zon_time00
O0096EastgateexpressR222026-09-03T13:00:00Z2026-09-03T21:00:00Zdelivered_late700
O0097EastgateexpressR212026-09-04T06:00:00Z2026-09-04T14:00:00Zdelivered_late700
O0098EastgateexpressR222026-09-05T07:00:00Z2026-09-05T15:00:00Zoverdue_open013500
O0099EastgateexpressR212026-09-06T08:00:00Z2026-09-06T16:00:00Zdelivered_late700
O0100EastgateexpressR222026-09-07T09:00:00Z2026-09-07T17:00:00Zdelivered_late700
O0101EastgateexpressR212026-09-08T10:00:00Z2026-09-08T18:00:00Zon_time00
O0102EastgateexpressR222026-09-09T11:00:00Z2026-09-09T19:00:00Zdelivered_late700
O0103EastgateexpressR212026-09-10T12:00:00Z2026-09-10T20:00:00Zdelivered_late700
O0104EastgateexpressR222026-09-11T13:00:00Z2026-09-11T21:00:00Zon_time00
O0105EastgateexpressR212026-09-12T06:00:00Z2026-09-12T14:00:00Zdelivered_late700
O0106EastgateexpressR222026-09-13T07:00:00Z2026-09-13T15:00:00Zdelivered_late700
O0107EastgateexpressR212026-09-01T08:00:00Z2026-09-01T16:00:00Zon_time00
O0108EastgateexpressR222026-09-02T09:00:00Z2026-09-02T17:00:00Zdelivered_late700
O0109EastgateexpressR212026-09-03T10:00:00Z2026-09-03T18:00:00Zdelivered_late700
O0110EastgateexpressR222026-09-04T11:00:00Z2026-09-04T19:00:00Zcancelled00
O0111EastgateexpressR212026-09-05T12:00:00Z2026-09-05T20:00:00Zdelivered_late700
O0112EastgateexpressR222026-09-06T13:00:00Z2026-09-06T21:00:00Zdelivered_late700
O0113EastgateexpressR212026-09-07T06:00:00Z2026-09-07T14:00:00Zon_time00
O0114EastgateexpressR222026-09-08T07:00:00Z2026-09-08T15:00:00Zdelivered_late700
O0115EastgateexpressR212026-09-09T08:00:00Z2026-09-09T16:00:00Zoverdue_open07680
O0116EastgateexpressR222026-09-10T09:00:00Z2026-09-10T17:00:00Zon_time00
O0117EastgateexpressR212026-09-11T10:00:00Z2026-09-11T18:00:00Zdelivered_late700
O0118EastgateexpressR222026-09-12T11:00:00Z2026-09-12T19:00:00Zdelivered_late700
O0119EastgateexpressR212026-09-13T12:00:00Z2026-09-13T20:00:00Zon_time00
O0120EastgateexpressR222026-09-14T21:00:00Z2026-09-15T05:00:00Znot_mature00
O0121WesthillstandardR312026-09-01T06:00:00Z2026-09-02T06:00:00Zcancelled00
O0122WesthillstandardR322026-09-02T07:00:00Z2026-09-03T07:00:00Zdelivered_late900
O0123WesthillstandardR312026-09-03T08:00:00Z2026-09-04T08:00:00Zon_time00
O0124WesthillstandardR322026-09-04T09:00:00Z2026-09-05T09:00:00Zon_time00
O0125WesthillstandardR312026-09-05T10:00:00Z2026-09-06T10:00:00Zon_time00
O0126WesthillstandardR322026-09-06T11:00:00Z2026-09-07T11:00:00Zon_time00
O0127WesthillstandardR312026-09-07T12:00:00Z2026-09-08T12:00:00Zdelivered_late900
O0128WesthillstandardR322026-09-08T13:00:00Z2026-09-09T13:00:00Zon_time00
O0129WesthillstandardR312026-09-09T06:00:00Z2026-09-10T06:00:00Zon_time00
O0130WesthillstandardR322026-09-10T07:00:00Z2026-09-11T07:00:00Zon_time00
O0131WesthillstandardR312026-09-11T08:00:00Z2026-09-12T08:00:00Zon_time00
O0132WesthillstandardR322026-09-12T09:00:00Z2026-09-13T09:00:00Zdelivered_late900
O0133WesthillstandardR312026-09-13T10:00:00Z2026-09-14T10:00:00Zon_time00
O0134WesthillstandardR322026-09-01T11:00:00Z2026-09-02T11:00:00Zon_time00
O0135WesthillstandardR312026-09-02T12:00:00Z2026-09-03T12:00:00Zon_time00
O0136WesthillstandardR322026-09-03T13:00:00Z2026-09-04T13:00:00Zon_time00
O0137WesthillstandardR312026-09-04T06:00:00Z2026-09-05T06:00:00Zdelivered_late900
O0138WesthillstandardR322026-09-05T07:00:00Z2026-09-06T07:00:00Zoverdue_open012540
O0139WesthillstandardR312026-09-06T08:00:00Z2026-09-07T08:00:00Zon_time00
O0140WesthillstandardR322026-09-07T09:00:00Z2026-09-08T09:00:00Zon_time00
O0141WesthillstandardR312026-09-08T10:00:00Z2026-09-09T10:00:00Zon_time00
O0142WesthillstandardR322026-09-09T11:00:00Z2026-09-10T11:00:00Zdelivered_late900
O0143WesthillstandardR312026-09-10T12:00:00Z2026-09-11T12:00:00Zon_time00
O0144WesthillstandardR322026-09-11T13:00:00Z2026-09-12T13:00:00Zon_time00
O0145WesthillstandardR312026-09-12T06:00:00Z2026-09-13T06:00:00Zon_time00
O0146WesthillstandardR322026-09-13T07:00:00Z2026-09-14T07:00:00Zon_time00
O0147WesthillstandardR312026-09-01T08:00:00Z2026-09-02T08:00:00Zdelivered_late900
O0148WesthillstandardR322026-09-02T09:00:00Z2026-09-03T09:00:00Zon_time00
O0149WesthillstandardR312026-09-03T10:00:00Z2026-09-04T10:00:00Zon_time00
O0150WesthillstandardR322026-09-04T11:00:00Z2026-09-05T11:00:00Zcancelled00
O0151WesthillstandardR312026-09-05T12:00:00Z2026-09-06T12:00:00Zon_time00
O0152WesthillstandardR322026-09-06T13:00:00Z2026-09-07T13:00:00Zdelivered_late900
O0153WesthillstandardR312026-09-07T06:00:00Z2026-09-08T06:00:00Zon_time00
O0154WesthillstandardR322026-09-08T07:00:00Z2026-09-09T07:00:00Zon_time00
O0155WesthillstandardR312026-09-09T08:00:00Z2026-09-10T08:00:00Zoverdue_open06720
O0156WesthillstandardR322026-09-14T21:00:00Z2026-09-15T21:00:00Znot_mature00
O0157WesthillexpressR312026-09-01T06:00:00Z2026-09-01T14:00:00Zcancelled00
O0158WesthillexpressR322026-09-02T07:00:00Z2026-09-02T15:00:00Zdelivered_late900
O0159WesthillexpressR312026-09-03T08:00:00Z2026-09-03T16:00:00Zon_time00
O0160WesthillexpressR322026-09-04T09:00:00Z2026-09-04T17:00:00Zon_time00
O0161WesthillexpressR312026-09-05T10:00:00Z2026-09-05T18:00:00Zdelivered_late900
O0162WesthillexpressR322026-09-06T11:00:00Z2026-09-06T19:00:00Zdelivered_late900
O0163WesthillexpressR312026-09-07T12:00:00Z2026-09-07T20:00:00Zon_time00
O0164WesthillexpressR322026-09-08T13:00:00Z2026-09-08T21:00:00Zon_time00
O0165WesthillexpressR312026-09-09T06:00:00Z2026-09-09T14:00:00Zdelivered_late900
O0166WesthillexpressR322026-09-10T07:00:00Z2026-09-10T15:00:00Zdelivered_late900
O0167WesthillexpressR312026-09-11T08:00:00Z2026-09-11T16:00:00Zon_time00
O0168WesthillexpressR322026-09-12T09:00:00Z2026-09-12T17:00:00Zon_time00
O0169WesthillexpressR312026-09-13T10:00:00Z2026-09-13T18:00:00Zdelivered_late900
O0170WesthillexpressR322026-09-01T11:00:00Z2026-09-01T19:00:00Zdelivered_late900
O0171WesthillexpressR312026-09-02T12:00:00Z2026-09-02T20:00:00Zon_time00
O0172WesthillexpressR322026-09-03T13:00:00Z2026-09-03T21:00:00Zon_time00
O0173WesthillexpressR312026-09-04T06:00:00Z2026-09-04T14:00:00Zdelivered_late900
O0174WesthillexpressR322026-09-05T07:00:00Z2026-09-05T15:00:00Zoverdue_open013500
O0175WesthillexpressR312026-09-06T08:00:00Z2026-09-06T16:00:00Zon_time00
O0176WesthillexpressR322026-09-07T09:00:00Z2026-09-07T17:00:00Zon_time00
O0177WesthillexpressR312026-09-08T10:00:00Z2026-09-08T18:00:00Zdelivered_late900
O0178WesthillexpressR322026-09-09T11:00:00Z2026-09-09T19:00:00Zdelivered_late900
O0179WesthillexpressR312026-09-10T12:00:00Z2026-09-10T20:00:00Zon_time00
O0180WesthillexpressR322026-09-14T21:00:00Z2026-09-15T05:00:00Znot_mature00
O0181SouthbaystandardR412026-09-01T06:00:00Z2026-09-02T06:00:00Zcancelled00
O0182SouthbaystandardR422026-09-02T07:00:00Z2026-09-03T07:00:00Zdelivered_late1100
O0183SouthbaystandardR412026-09-03T08:00:00Z2026-09-04T08:00:00Zon_time00
O0184SouthbaystandardR422026-09-04T09:00:00Z2026-09-05T09:00:00Zon_time00
O0185SouthbaystandardR412026-09-05T10:00:00Z2026-09-06T10:00:00Zon_time00
O0186SouthbaystandardR422026-09-06T11:00:00Z2026-09-07T11:00:00Zon_time00
O0187SouthbaystandardR412026-09-07T12:00:00Z2026-09-08T12:00:00Zon_time00
O0188SouthbaystandardR422026-09-08T13:00:00Z2026-09-09T13:00:00Zdelivered_late1100
O0189SouthbaystandardR412026-09-09T06:00:00Z2026-09-10T06:00:00Zon_time00
O0190SouthbaystandardR422026-09-10T07:00:00Z2026-09-11T07:00:00Zon_time00
O0191SouthbaystandardR412026-09-11T08:00:00Z2026-09-12T08:00:00Zon_time00
O0192SouthbaystandardR422026-09-12T09:00:00Z2026-09-13T09:00:00Zon_time00
O0193SouthbaystandardR412026-09-13T10:00:00Z2026-09-14T10:00:00Zon_time00
O0194SouthbaystandardR422026-09-01T11:00:00Z2026-09-02T11:00:00Zdelivered_late1100
O0195SouthbaystandardR412026-09-02T12:00:00Z2026-09-03T12:00:00Zon_time00
O0196SouthbaystandardR422026-09-03T13:00:00Z2026-09-04T13:00:00Zon_time00
O0197SouthbaystandardR412026-09-04T06:00:00Z2026-09-05T06:00:00Zon_time00
O0198SouthbaystandardR422026-09-05T07:00:00Z2026-09-06T07:00:00Zoverdue_open012540
O0199SouthbaystandardR412026-09-06T08:00:00Z2026-09-07T08:00:00Zon_time00
O0200SouthbaystandardR422026-09-07T09:00:00Z2026-09-08T09:00:00Zdelivered_late1100
O0201SouthbaystandardR412026-09-08T10:00:00Z2026-09-09T10:00:00Zon_time00
O0202SouthbaystandardR422026-09-09T11:00:00Z2026-09-10T11:00:00Zon_time00
O0203SouthbaystandardR412026-09-10T12:00:00Z2026-09-11T12:00:00Zon_time00
O0204SouthbaystandardR422026-09-11T13:00:00Z2026-09-12T13:00:00Zon_time00
O0205SouthbaystandardR412026-09-12T06:00:00Z2026-09-13T06:00:00Zon_time00
O0206SouthbaystandardR422026-09-13T07:00:00Z2026-09-14T07:00:00Zdelivered_late1100
O0207SouthbaystandardR412026-09-01T08:00:00Z2026-09-02T08:00:00Zon_time00
O0208SouthbaystandardR422026-09-02T09:00:00Z2026-09-03T09:00:00Zon_time00
O0209SouthbaystandardR412026-09-03T10:00:00Z2026-09-04T10:00:00Zon_time00
O0210SouthbaystandardR422026-09-14T21:00:00Z2026-09-15T21:00:00Zcancelled00
O0211SouthbayexpressR412026-09-01T06:00:00Z2026-09-01T14:00:00Zcancelled00
O0212SouthbayexpressR422026-09-02T07:00:00Z2026-09-02T15:00:00Zdelivered_late1100
O0213SouthbayexpressR412026-09-03T08:00:00Z2026-09-03T16:00:00Zon_time00
O0214SouthbayexpressR422026-09-04T09:00:00Z2026-09-04T17:00:00Zon_time00
O0215SouthbayexpressR412026-09-05T10:00:00Z2026-09-05T18:00:00Zon_time00
O0216SouthbayexpressR422026-09-14T21:00:00Z2026-09-15T05:00:00Znot_mature00
learner/materials/rules.json Read the full fileDownload file
{
  "cutoff": "2026-09-15T00:00:00Z",
  "late_target": 0.1,
  "min_sample": 15,
  "review_gap_pp": 5,
  "priority_gap_pp": 15,
  "standard_weight": 0.5,
  "express_weight": 0.5
}
learner/materials/data-dictionary.md Read the full fileDownload file

Data dictionary and decision rules

Assignment brief

You join the cold-chain fulfilment operations team. The operations lead needs to decide which orders and hubs to review first, where export controls failed, and what the next operations workbench must deliver. The four hubs are Harbour, Eastgate, Westhill and Southbay. Standard service promises delivery within 24 hours and express within 8 hours. Use the actual due_at value in orders.csv for each order.

The review cutoff is 2026-09-15T00:00:00Z, defined in rules.json. Convert every business timestamp to UTC. Records can contain events after the cutoff so that you can test whether a historical review accidentally uses future information.

Orders

One row in orders.csv is one order. order_id is a unique text identifier; keep its leading zeros. hub is the operating hub, service is standard or express, and route identifies the route. created_at and due_at are timezone-aware ISO 8601 timestamps. Counting event rows is not a valid way to count orders.

Event feeds and canonical schema

Feed A maps event_id to event_id, order_ref to order_id, hub to hub, service to service, event to kind, and event_time to happened_at.

Feed B maps id to event_id, shipment.number to order_id, shipment.station to hub, shipment.product to service, and at_ms to happened_at. at_ms is an integer Unix timestamp in milliseconds. Map OPEN, COLLECT, DROP and VOID to created, picked_up, delivered and cancelled respectively.

The canonical event contains event_id, order_id, hub, service, kind and happened_at. happened_at is UTC ISO 8601 with a Z suffix. Validate required fields, action names and dimensions. Reject timezone-free timestamps and non-integer epochs. Do not change the raw inputs.

Identical canonical content under the same event_id is an exact replay: retain one event and list every removed replay. Different content under one immutable event_id is a conflict: quarantine the entire group. Never accept the first arrival and silently overwrite it later. Keep the source filename, 1-based line number and reason for every rejected record or replay. Reconcile raw records = canonical events + quarantined records + removed replays.

Historical fulfilment cohort

Group events by order_id and retain only events with happened_at <= cutoff. A visible cancellation takes precedence and is excluded from the mature denominator. A non-cancelled order with due_at > cutoff is not_mature. Otherwise, no visible delivery means overdue_open; the first visible delivery after due_at means delivered_late; delivery at or before due_at means on_time. Exactly at the due timestamp is mature, and delivery exactly at that timestamp is on time.

Eligible mature orders = on_time + delivered_late + overdue_open. Late orders = delivered_late + overdue_open. Never classify cancellation or an order not yet due as successful delivery. Keep delivered lateness minutes (delivery minus due_at) separate from open overdue minutes (cutoff minus due_at). The inputs do not contain actual refunds, damaged-goods values or costs, so do not calculate those amounts.

Service review

The fixed late-rate target is 10%, and the minimum mature sample is 15 per hub/service cell. gap_pp = (late_rate - 0.10) * 100, measured in percentage points. Apply sample size first: below 15 is More data needed. A gap above 15 points is Priority review; above 5 and at most 15 is Review needed; at most 5 is Within threshold. These are operational triage rules, not a statistical finding of unfair treatment.

For a comparable service mix, give standard and express equal 50% weights. Calculate a hub's standardized late rate only when both service cells meet the minimum sample. Otherwise retain a missing value and state which cell is insufficient. Do not impute an overall mean or rank a small sample as the best hub. Separate observations, possible explanations and causal claims.

Access logs and policy

One access-log.csv row is one request. request_id is unique; at is UTC. user, session and role are gateway request context. method and path identify the resource; status is the response code; rows and bytes are gateway response counts. These counts do not prove unique customers, file retention or subsequent use.

access-policy.json defines the baseline. An operator can read only the assigned hub and cannot export. A supervisor or approved service role can export. A session lasts 30 minutes after a successful login: exactly 30 minutes is valid, and later requests must be rejected. Failed logins do not renew sessions. A 401 is a denied attempt, not confirmed disclosure. svc-archive is approved, so a frequent large export is not automatically suspicious. The IP ranges are documentation addresses; the logs cannot establish geography, a natural person's identity or the actual access path. Endpoint and VPN evidence would be needed.

Steps

  1. Group the order-level review by hub and service. Calculate mature and late counts from orders, using a pivot table or Python; do not reconstruct counts from rounded percentages.
  1. Calculate late/eligible and gap_pp against 10%. Apply the minimum sample first, then the >15 and >5 point boundaries. Test values exactly at 5 and 15.
  1. Write service-review.csv with count, rate, target, gap and recommendation for every cell.
  1. Use a 50/50 standard/express mix for each hub. If either cell has fewer than 15 mature orders, leave the standardized hub value missing and mark More data needed.
  1. Compare raw and standardized rates side by side. Explain Eastgate's larger express share. Standardization alone does not establish cause.
  1. Write review-memo.md naming the insufficient Southbay cell and the number of additional mature orders needed, plus a review action and conclusions the data cannot support.

Complete outputs

Service performance review memorandum

Priority

Review Harbour express (18/18) and Harbour standard (14/37) first, along with Eastgate express (26/37). Southbay express has only four mature orders and one late order. Collect more data before treating its 25% rate as stable.

HubRaw late rateStandardized late rate
Eastgate56.36%49.02%
Southbay21.88%More data needed
Harbour58.18%68.92%
Westhill36.36%38.64%

Method

For each hub/service cell, late_rate = late/eligible and gap_pp = (late_rate - 0.10) * 100. Apply the sample check before thresholds. A gap exactly at 15 points is Review needed, not Priority review. A gap exactly at 5 points is Within threshold.

Standardized rate = 0.5 * standard rate + 0.5 * express rate. Eastgate express accounts for 37/55 mature orders. Its raw 56.36% rate becomes 49.02% at equal weights. Harbour express accounts for only 18/55, so its standardized rate rises from 58.18% to 68.92%. Overall differences partly reflect service mix and should not be attributed entirely to hub performance.

Next evidence

Southbay express needs at least 11 more mature orders to reach the operational threshold of 15; the added observations can change its rate. Hold the observation period and cohort rules consistent, retaining cancelled and not-mature records. Fifteen is a review threshold, not proof of statistical significance.

Weather, route distance, customer appointments and shift schedules are absent. This comparison does not establish individual responsibility, unfair treatment or an improvement forecast. Inspect Harbour express handovers and departures, then compare like routes, services and time periods before designing a process experiment.

Download file

Reference answers

instructor/answers/service-review.csv Read the full fileDownload file
hubserviceeligiblelatelate_ratetargetgap_ppreview
Eastgateexpress37260.7027030.160.27Priority review
Eastgatestandard1850.2777780.117.778Priority review
Harbourexpress18181.00.190.0Priority review
Harbourstandard37140.3783780.127.838Priority review
Southbayexpress410.250.115.0More data needed
Southbaystandard2860.2142860.111.429Review needed
Westhillexpress22110.50.140.0Priority review
Westhillstandard3390.2727270.117.273Priority review
instructor/answers/standardized-comparison.csv Read the full fileDownload file
hubstandardized_late_ratestatus
Eastgate0.49024Comparable
Harbour0.689189Comparable
SouthbayMore data needed
Westhill0.386363Comparable
Complete reference implementation Read the full fileDownload file
"""Reference implementation for the Ape Intern cold-chain operations lab."""
import csv,json
from collections import defaultdict,Counter
from datetime import datetime,timezone
from pathlib import Path
from urllib.parse import urlparse,parse_qs
UTC=timezone.utc
KINDS={'OPEN':'created','COLLECT':'picked_up','DROP':'delivered','VOID':'cancelled'}
HUBS={'Harbour','Eastgate','Westhill','Southbay'}
def parse_time(value):
    t=datetime.fromisoformat(value.replace('Z','+00:00'))
    if t.tzinfo is None:raise ValueError('timezone_required')
    return t.astimezone(UTC)
def iso(t):return t.isoformat(timespec='seconds').replace('+00:00','Z')
def readcsv(p):
    with Path(p).open(encoding='utf-8-sig',newline='') as f:return list(csv.DictReader(f))
def writecsv(p,rows,fields=None):
    rows=list(rows)
    with Path(p).open('w',encoding='utf-8-sig',newline='') as f:
        w=csv.DictWriter(f,fieldnames=fields or list(rows[0]));w.writeheader();w.writerows(rows)
def dump(p,value):Path(p).write_text(json.dumps(value,ensure_ascii=False,indent=2)+'\n')
def _normalize(record,source):
    if source=='A':
        e=dict(event_id=record['event_id'],order_id=record['order_ref'],hub=record['hub'],service=record['service'],kind=record['event'],happened_at=iso(parse_time(record['event_time'])))
    else:
        ms=record['at_ms']
        if type(ms) is not int:raise ValueError('epoch_must_be_integer')
        e=dict(event_id=record['id'],order_id=record['shipment']['number'],hub=record['shipment']['station'],service=record['shipment']['product'],kind=KINDS[record['action']],happened_at=iso(datetime.fromtimestamp(ms/1000,UTC)))
    if e['kind'] not in KINDS.values():raise ValueError('unsupported_event')
    if e['hub'] not in HUBS or e['service'] not in {'standard','express'}:raise ValueError('unknown_dimension')
    if not e['event_id'] or not e['order_id']:raise ValueError('empty_key')
    return e

def normalize(record,source):
    try:return _normalize(record,source)
    except (KeyError,TypeError,OverflowError) as error:raise ValueError(str(error).strip("'")) from error

def ingest(data):
    grouped=defaultdict(list);rejected=[];duplicates=[]
    for source,name in [('A','dispatch-a.jsonl'),('B','courier-b.jsonl')]:
        for line,text in enumerate((data/name).read_text().splitlines(),1):
            loc={'source':name,'line':line}
            try:
                event=normalize(json.loads(text),source);grouped[event['event_id']].append((event,loc))
            except (ValueError,KeyError,TypeError,OverflowError) as ex:
                rejected.append(dict(loc,reason=str(ex).strip("'")))
    accepted=[]
    for eid,items in grouped.items():
        distinct={json.dumps(e,sort_keys=True,ensure_ascii=False) for e,loc in items}
        if len(distinct)>1:
            rejected.extend(dict(loc,reason='immutable_id_conflict') for e,loc in items);continue
        accepted.append(items[0][0])
        duplicates.extend(dict(loc,event_id=eid,reason='exact_replay') for e,loc in items[1:])
    accepted.sort(key=lambda e:(e['happened_at'],e['event_id']))
    return accepted,rejected,duplicates

def classify_order(order,events,cutoff):
    # Only facts available at cutoff can influence a retrospective result.
    visible=[e for e in events if parse_time(e['happened_at'])<=cutoff]
    visible.sort(key=lambda e:parse_time(e['happened_at']))
    delivered=[parse_time(e['happened_at']) for e in visible if e['kind']=='delivered']
    cancelled=any(e['kind']=='cancelled' for e in visible)
    due=parse_time(order['due_at'])
    if cancelled:state='cancelled'
    elif due>cutoff:state='not_mature'
    elif not delivered:state='overdue_open'
    elif min(delivered)>due:state='delivered_late'
    else:state='on_time'
    delay=round((min(delivered)-due).total_seconds()/60) if state=='delivered_late' else 0
    overdue=round((cutoff-due).total_seconds()/60) if state=='overdue_open' else 0
    return dict(order,cohort=state,late_minutes=delay,overdue_minutes=overdue)

def aggregate(rows,keys):
    groups=defaultdict(list)
    for row in rows:groups[tuple(row[k] for k in keys)].append(row)
    result=[]
    for dims,records in sorted(groups.items()):
        counts=Counter(r['cohort'] for r in records)
        eligible=sum(counts[x] for x in ['on_time','delivered_late','overdue_open'])
        late=counts['delivered_late']+counts['overdue_open']
        result.append(dict(zip(keys,dims),total=len(records),eligible=eligible,late=late,late_rate=round(late/eligible,6) if eligible else None,on_time=counts['on_time'],delivered_late=counts['delivered_late'],overdue_open=counts['overdue_open'],cancelled=counts['cancelled'],not_mature=counts['not_mature'],delivered_late_minutes=sum(r['late_minutes'] for r in records),open_overdue_minutes=sum(r['overdue_minutes'] for r in records)))
    return result

def service_band(rate,n,rules):
    if n<rules['min_sample']:return 'More data needed'
    gap=(rate-rules['late_target'])*100
    if gap>rules['priority_gap_pp']:return 'Priority review'
    if gap>rules['review_gap_pp']:return 'Review needed'
    return 'Within threshold'
def fairness(hub_tiers,rules):
    rows=[]
    for x in hub_tiers:
        rate=x['late_rate'];rows.append(dict(hub=x['hub'],service=x['service'],eligible=x['eligible'],late=x['late'],late_rate=rate,target=rules['late_target'],gap_pp=round((rate-rules['late_target'])*100,3) if rate is not None else None,review=service_band(rate,x['eligible'],rules)))
    standardized=[]
    for hub in sorted(HUBS):
        parts=[r for r in rows if r['hub']==hub]
        enough=len(parts)==2 and all(r['eligible']>=rules['min_sample'] for r in parts)
        value=sum(r['late_rate']*rules[r['service']+'_weight'] for r in parts) if enough else None
        standardized.append(dict(hub=hub,standardized_late_rate=round(value,6) if value is not None else None,status='Comparable' if enough else 'More data needed'))
    return rows,standardized

def investigate(logs,policy):
    logins={};findings=[]
    for row in sorted(logs,key=lambda r:(r['at'],r['request_id'])):
        t=parse_time(row['at']);status=int(row['status']);route=urlparse(row['path']);query=parse_qs(route.query)
        if route.path=='/login' and status==200:logins[(row['user'],row['session'])]=t;continue
        if status!=200:continue
        types=[]
        if route.path=='/export' and row['role'] not in policy['export_roles']:types.append('unauthorised_export')
        hub=query.get('hub',[''])[0]
        if row['role']=='operator' and hub and hub!=policy['operator_hub'].get(row['user']):types.append('hub_scope_violation')
        login=logins.get((row['user'],row['session']))
        if login is None or (t-login).total_seconds()>policy['session_ttl_minutes']*60:types.append('expired_or_missing_session')
        if types:findings.append(dict(request_id=row['request_id'],at=row['at'],user=row['user'],session=row['session'],finding=';'.join(types),status=status,rows=int(row['rows']),bytes=int(row['bytes'])))
    return findings

def solve(data,out):
    data=Path(data);out=Path(out);out.mkdir(parents=True,exist_ok=True)
    events,rejects,dups=ingest(data)
    (out/'canonical-events.jsonl').write_text(''.join(json.dumps(e,ensure_ascii=False)+'\n' for e in events))
    writecsv(out/'rejected.csv',rejects);writecsv(out/'duplicates.csv',dups)
    rules=json.loads((data/'rules.json').read_text());cutoff=parse_time(rules['cutoff'])
    by_order=defaultdict(list)
    for e in events:by_order[e['order_id']].append(e)
    orders=readcsv(data/'orders.csv')
    records=[classify_order(o,by_order[o['order_id']],cutoff) for o in orders]
    writecsv(out/'order-review.csv',records)
    hubs=aggregate(records,['hub']);tiers=aggregate(records,['hub','service']);routes=aggregate(records,['route'])
    writecsv(out/'hub-metrics.csv',hubs);writecsv(out/'route-metrics.csv',routes)
    bands,std=fairness(tiers,rules)
    writecsv(out/'service-review.csv',bands);writecsv(out/'standardized-comparison.csv',std)
    findings=investigate(readcsv(data/'access-log.csv'),json.loads((data/'access-policy.json').read_text()))
    writecsv(out/'security-findings.csv',findings)
    summary=dict(orders=len(orders),accepted_events=len(events),rejected=len(rejects),duplicates=len(dups),cohorts=dict(Counter(r['cohort'] for r in records)),hubs=hubs,service_review=bands,standardized=std,security=dict(flagged_requests=len(findings),potential_export_rows=sum(f['rows'] for f in findings if 'unauthorised_export' in f['finding']),potential_export_bytes=sum(f['bytes'] for f in findings if 'unauthorised_export' in f['finding']),findings=findings))
    dump(out/'results.json',summary)
    return summary
if __name__=='__main__':
    import sys
    print(json.dumps(solve(sys.argv[1],sys.argv[2]),ensure_ascii=False,indent=2))

Each task is worth 20 points. Reach at least 14 and correct all critical rule errors before the next review. Editing raw inputs, silently dropping records, including not-yet-due orders in the denominator, counting 401 attempts as disclosure, ranking an insufficient sample or treating a UI filter as authorization requires correction and re-testing.

  • Stratified denominator and target: 6
  • Threshold boundaries and sample precedence: 5
  • Standardization and missing values: 5
  • Explanation and follow-up sampling: 4