Choose your marketSelected market: United States
Deloitte Virtual Internship / Task 05
An original Ape Intern practical · Task 05Operations workbench delivery proposal
Turn the preceding evidence into a scoped, estimated and testable delivery proposal.
Start with the completed outputs, then use the materials to deliver your own work.
Read complete output firstMaterials
learner/materials/stakeholder-brief.md Read the full file
Download fileWorkbench stakeholder brief
Operations lead: Start each morning with orders that are already overdue and still undelivered, then inspect the hub and route. Historical late deliveries support the review but should not hide the active queue. Filter by hub, service and cohort, open an order's event timeline, and show the review cutoff and last successful data update.
Hub lead: Do not rank staff or hubs using overall rates with different service mixes. Southbay express has too little data for a stable comparison. A route note is an investigation lead, not proof of an employee's responsibility.
Security lead: Operators may read only their assigned hubs. Exports require supervisor or service permissions, checked on the server for every request together with session validity. Use the existing corporate identity service and do not add a password store. Choosing a hub in the UI does not grant access.
Delivery lead: Phase one is a read-only workbench, order evidence timeline and controlled export design. Refunds, dispatch writes and customer notifications are excluded. Integration depends on client identity, gateway and order interfaces. Estimate effort, define acceptance, failure handling and rollback. No budget, contractual response SLA, concurrency target or launch date has been agreed; list them as decisions to confirm.
learner/checkpoints/security-findings.csv Read the full file
Download file| request_id | at | user | session | finding | status | rows | bytes |
|---|---|---|---|---|---|---|---|
| Q0058 | 2026-09-10T09:41:00Z | op-7 | sus-7 | unauthorised_export;hub_scope_violation | 200 | 1200 | 96000 |
| Q0059 | 2026-09-10T09:42:00Z | op-7 | sus-7 | unauthorised_export;hub_scope_violation | 200 | 1200 | 96000 |
| Q0060 | 2026-09-10T09:43:00Z | op-7 | sus-7 | unauthorised_export;hub_scope_violation | 200 | 1200 | 96000 |
| Q0061 | 2026-09-10T09:44:00Z | op-7 | sus-7 | unauthorised_export;hub_scope_violation | 200 | 1200 | 96000 |
| Q0062 | 2026-09-10T09:45:00Z | op-7 | sus-7 | unauthorised_export;hub_scope_violation | 200 | 1200 | 96000 |
| Q0063 | 2026-09-10T09:46:00Z | op-7 | sus-7 | unauthorised_export;hub_scope_violation | 200 | 1200 | 96000 |
| Q0069 | 2026-09-10T11:15:00Z | op-2 | expired-2 | expired_or_missing_session | 200 | 50 | 10000 |
learner/checkpoints/standardized-comparison.csv Read the full file
Download file| hub | standardized_late_rate | status |
|---|---|---|
| Eastgate | 0.49024 | Comparable |
| Harbour | 0.689189 | Comparable |
| Southbay | More data needed | |
| Westhill | 0.386363 | Comparable |
learner/checkpoints/order-review.csv Read the full file
Download file| order_id | hub | service | route | created_at | due_at | cohort | late_minutes | overdue_minutes |
|---|---|---|---|---|---|---|---|---|
| O0001 | Harbour | standard | R11 | 2026-09-01T06:00:00Z | 2026-09-02T06:00:00Z | cancelled | 0 | 0 |
| O0002 | Harbour | standard | R12 | 2026-09-02T07:00:00Z | 2026-09-03T07:00:00Z | delivered_late | 50 | 0 |
| O0003 | Harbour | standard | R11 | 2026-09-03T08:00:00Z | 2026-09-04T08:00:00Z | on_time | 0 | 0 |
| O0004 | Harbour | standard | R12 | 2026-09-04T09:00:00Z | 2026-09-05T09:00:00Z | on_time | 0 | 0 |
| O0005 | Harbour | standard | R11 | 2026-09-05T10:00:00Z | 2026-09-06T10:00:00Z | delivered_late | 50 | 0 |
| O0006 | Harbour | standard | R12 | 2026-09-06T11:00:00Z | 2026-09-07T11:00:00Z | on_time | 0 | 0 |
| O0007 | Harbour | standard | R11 | 2026-09-07T12:00:00Z | 2026-09-08T12:00:00Z | on_time | 0 | 0 |
| O0008 | Harbour | standard | R12 | 2026-09-08T13:00:00Z | 2026-09-09T13:00:00Z | delivered_late | 50 | 0 |
| O0009 | Harbour | standard | R11 | 2026-09-09T06:00:00Z | 2026-09-10T06:00:00Z | on_time | 0 | 0 |
| O0010 | Harbour | standard | R12 | 2026-09-10T07:00:00Z | 2026-09-11T07:00:00Z | on_time | 0 | 0 |
| O0011 | Harbour | standard | R11 | 2026-09-11T08:00:00Z | 2026-09-12T08:00:00Z | delivered_late | 50 | 0 |
| O0012 | Harbour | standard | R12 | 2026-09-12T09:00:00Z | 2026-09-13T09:00:00Z | on_time | 0 | 0 |
| O0013 | Harbour | standard | R11 | 2026-09-13T10:00:00Z | 2026-09-14T10:00:00Z | on_time | 0 | 0 |
| O0014 | Harbour | standard | R12 | 2026-09-01T11:00:00Z | 2026-09-02T11:00:00Z | delivered_late | 50 | 0 |
| O0015 | Harbour | standard | R11 | 2026-09-02T12:00:00Z | 2026-09-03T12:00:00Z | on_time | 0 | 0 |
| O0016 | Harbour | standard | R12 | 2026-09-03T13:00:00Z | 2026-09-04T13:00:00Z | on_time | 0 | 0 |
| O0017 | Harbour | standard | R11 | 2026-09-04T06:00:00Z | 2026-09-05T06:00:00Z | delivered_late | 50 | 0 |
| O0018 | Harbour | standard | R12 | 2026-09-05T07:00:00Z | 2026-09-06T07:00:00Z | overdue_open | 0 | 12540 |
| O0019 | Harbour | standard | R11 | 2026-09-06T08:00:00Z | 2026-09-07T08:00:00Z | on_time | 0 | 0 |
| O0020 | Harbour | standard | R12 | 2026-09-07T09:00:00Z | 2026-09-08T09:00:00Z | delivered_late | 50 | 0 |
| O0021 | Harbour | standard | R11 | 2026-09-08T10:00:00Z | 2026-09-09T10:00:00Z | on_time | 0 | 0 |
| O0022 | Harbour | standard | R12 | 2026-09-09T11:00:00Z | 2026-09-10T11:00:00Z | on_time | 0 | 0 |
| O0023 | Harbour | standard | R11 | 2026-09-10T12:00:00Z | 2026-09-11T12:00:00Z | delivered_late | 50 | 0 |
| O0024 | Harbour | standard | R12 | 2026-09-11T13:00:00Z | 2026-09-12T13:00:00Z | on_time | 0 | 0 |
| O0025 | Harbour | standard | R11 | 2026-09-12T06:00:00Z | 2026-09-13T06:00:00Z | on_time | 0 | 0 |
| O0026 | Harbour | standard | R12 | 2026-09-13T07:00:00Z | 2026-09-14T07:00:00Z | delivered_late | 50 | 0 |
| O0027 | Harbour | standard | R11 | 2026-09-01T08:00:00Z | 2026-09-02T08:00:00Z | on_time | 0 | 0 |
| O0028 | Harbour | standard | R12 | 2026-09-02T09:00:00Z | 2026-09-03T09:00:00Z | on_time | 0 | 0 |
| O0029 | Harbour | standard | R11 | 2026-09-03T10:00:00Z | 2026-09-04T10:00:00Z | delivered_late | 50 | 0 |
| O0030 | Harbour | standard | R12 | 2026-09-04T11:00:00Z | 2026-09-05T11:00:00Z | cancelled | 0 | 0 |
| O0031 | Harbour | standard | R11 | 2026-09-05T12:00:00Z | 2026-09-06T12:00:00Z | on_time | 0 | 0 |
| O0032 | Harbour | standard | R12 | 2026-09-06T13:00:00Z | 2026-09-07T13:00:00Z | delivered_late | 50 | 0 |
| O0033 | Harbour | standard | R11 | 2026-09-07T06:00:00Z | 2026-09-08T06:00:00Z | on_time | 0 | 0 |
| O0034 | Harbour | standard | R12 | 2026-09-08T07:00:00Z | 2026-09-09T07:00:00Z | on_time | 0 | 0 |
| O0035 | Harbour | standard | R11 | 2026-09-09T08:00:00Z | 2026-09-10T08:00:00Z | overdue_open | 0 | 6720 |
| O0036 | Harbour | standard | R12 | 2026-09-10T09:00:00Z | 2026-09-11T09:00:00Z | on_time | 0 | 0 |
| O0037 | Harbour | standard | R11 | 2026-09-11T10:00:00Z | 2026-09-12T10:00:00Z | on_time | 0 | 0 |
| O0038 | Harbour | standard | R12 | 2026-09-12T11:00:00Z | 2026-09-13T11:00:00Z | delivered_late | 50 | 0 |
| O0039 | Harbour | standard | R11 | 2026-09-13T12:00:00Z | 2026-09-14T12:00:00Z | on_time | 0 | 0 |
| O0040 | Harbour | standard | R12 | 2026-09-14T21:00:00Z | 2026-09-15T21:00:00Z | not_mature | 0 | 0 |
| O0041 | Harbour | express | R11 | 2026-09-01T06:00:00Z | 2026-09-01T14:00:00Z | cancelled | 0 | 0 |
| O0042 | Harbour | express | R12 | 2026-09-02T07:00:00Z | 2026-09-02T15:00:00Z | delivered_late | 50 | 0 |
| O0043 | Harbour | express | R11 | 2026-09-03T08:00:00Z | 2026-09-03T16:00:00Z | delivered_late | 50 | 0 |
| O0044 | Harbour | express | R12 | 2026-09-04T09:00:00Z | 2026-09-04T17:00:00Z | delivered_late | 50 | 0 |
| O0045 | Harbour | express | R11 | 2026-09-05T10:00:00Z | 2026-09-05T18:00:00Z | delivered_late | 50 | 0 |
| O0046 | Harbour | express | R12 | 2026-09-06T11:00:00Z | 2026-09-06T19:00:00Z | delivered_late | 50 | 0 |
| O0047 | Harbour | express | R11 | 2026-09-07T12:00:00Z | 2026-09-07T20:00:00Z | delivered_late | 50 | 0 |
| O0048 | Harbour | express | R12 | 2026-09-08T13:00:00Z | 2026-09-08T21:00:00Z | delivered_late | 50 | 0 |
| O0049 | Harbour | express | R11 | 2026-09-09T06:00:00Z | 2026-09-09T14:00:00Z | delivered_late | 50 | 0 |
| O0050 | Harbour | express | R12 | 2026-09-10T07:00:00Z | 2026-09-10T15:00:00Z | delivered_late | 50 | 0 |
| O0051 | Harbour | express | R11 | 2026-09-11T08:00:00Z | 2026-09-11T16:00:00Z | delivered_late | 50 | 0 |
| O0052 | Harbour | express | R12 | 2026-09-12T09:00:00Z | 2026-09-12T17:00:00Z | delivered_late | 50 | 0 |
| O0053 | Harbour | express | R11 | 2026-09-13T10:00:00Z | 2026-09-13T18:00:00Z | delivered_late | 50 | 0 |
| O0054 | Harbour | express | R12 | 2026-09-01T11:00:00Z | 2026-09-01T19:00:00Z | delivered_late | 50 | 0 |
| O0055 | Harbour | express | R11 | 2026-09-02T12:00:00Z | 2026-09-02T20:00:00Z | delivered_late | 50 | 0 |
| O0056 | Harbour | express | R12 | 2026-09-03T13:00:00Z | 2026-09-03T21:00:00Z | delivered_late | 50 | 0 |
| O0057 | Harbour | express | R11 | 2026-09-04T06:00:00Z | 2026-09-04T14:00:00Z | delivered_late | 50 | 0 |
| O0058 | Harbour | express | R12 | 2026-09-05T07:00:00Z | 2026-09-05T15:00:00Z | overdue_open | 0 | 13500 |
| O0059 | Harbour | express | R11 | 2026-09-06T08:00:00Z | 2026-09-06T16:00:00Z | delivered_late | 50 | 0 |
| O0060 | Harbour | express | R12 | 2026-09-14T21:00:00Z | 2026-09-15T05:00:00Z | not_mature | 0 | 0 |
| O0061 | Eastgate | standard | R21 | 2026-09-01T06:00:00Z | 2026-09-02T06:00:00Z | cancelled | 0 | 0 |
| O0062 | Eastgate | standard | R22 | 2026-09-02T07:00:00Z | 2026-09-03T07:00:00Z | delivered_late | 70 | 0 |
| O0063 | Eastgate | standard | R21 | 2026-09-03T08:00:00Z | 2026-09-04T08:00:00Z | on_time | 0 | 0 |
| O0064 | Eastgate | standard | R22 | 2026-09-04T09:00:00Z | 2026-09-05T09:00:00Z | on_time | 0 | 0 |
| O0065 | Eastgate | standard | R21 | 2026-09-05T10:00:00Z | 2026-09-06T10:00:00Z | on_time | 0 | 0 |
| O0066 | Eastgate | standard | R22 | 2026-09-06T11:00:00Z | 2026-09-07T11:00:00Z | delivered_late | 70 | 0 |
| O0067 | Eastgate | standard | R21 | 2026-09-07T12:00:00Z | 2026-09-08T12:00:00Z | on_time | 0 | 0 |
| O0068 | Eastgate | standard | R22 | 2026-09-08T13:00:00Z | 2026-09-09T13:00:00Z | on_time | 0 | 0 |
| O0069 | Eastgate | standard | R21 | 2026-09-09T06:00:00Z | 2026-09-10T06:00:00Z | on_time | 0 | 0 |
| O0070 | Eastgate | standard | R22 | 2026-09-10T07:00:00Z | 2026-09-11T07:00:00Z | delivered_late | 70 | 0 |
| O0071 | Eastgate | standard | R21 | 2026-09-11T08:00:00Z | 2026-09-12T08:00:00Z | on_time | 0 | 0 |
| O0072 | Eastgate | standard | R22 | 2026-09-12T09:00:00Z | 2026-09-13T09:00:00Z | on_time | 0 | 0 |
| O0073 | Eastgate | standard | R21 | 2026-09-13T10:00:00Z | 2026-09-14T10:00:00Z | on_time | 0 | 0 |
| O0074 | Eastgate | standard | R22 | 2026-09-01T11:00:00Z | 2026-09-02T11:00:00Z | delivered_late | 70 | 0 |
| O0075 | Eastgate | standard | R21 | 2026-09-02T12:00:00Z | 2026-09-03T12:00:00Z | on_time | 0 | 0 |
| O0076 | Eastgate | standard | R22 | 2026-09-03T13:00:00Z | 2026-09-04T13:00:00Z | on_time | 0 | 0 |
| O0077 | Eastgate | standard | R21 | 2026-09-04T06:00:00Z | 2026-09-05T06:00:00Z | on_time | 0 | 0 |
| O0078 | Eastgate | standard | R22 | 2026-09-05T07:00:00Z | 2026-09-06T07:00:00Z | overdue_open | 0 | 12540 |
| O0079 | Eastgate | standard | R21 | 2026-09-06T08:00:00Z | 2026-09-07T08:00:00Z | on_time | 0 | 0 |
| O0080 | Eastgate | standard | R22 | 2026-09-14T21:00:00Z | 2026-09-15T21:00:00Z | not_mature | 0 | 0 |
| O0081 | Eastgate | express | R21 | 2026-09-01T06:00:00Z | 2026-09-01T14:00:00Z | cancelled | 0 | 0 |
| O0082 | Eastgate | express | R22 | 2026-09-02T07:00:00Z | 2026-09-02T15:00:00Z | delivered_late | 70 | 0 |
| O0083 | Eastgate | express | R21 | 2026-09-03T08:00:00Z | 2026-09-03T16:00:00Z | on_time | 0 | 0 |
| O0084 | Eastgate | express | R22 | 2026-09-04T09:00:00Z | 2026-09-04T17:00:00Z | delivered_late | 70 | 0 |
| O0085 | Eastgate | express | R21 | 2026-09-05T10:00:00Z | 2026-09-05T18:00:00Z | delivered_late | 70 | 0 |
| O0086 | Eastgate | express | R22 | 2026-09-06T11:00:00Z | 2026-09-06T19:00:00Z | on_time | 0 | 0 |
| O0087 | Eastgate | express | R21 | 2026-09-07T12:00:00Z | 2026-09-07T20:00:00Z | delivered_late | 70 | 0 |
| O0088 | Eastgate | express | R22 | 2026-09-08T13:00:00Z | 2026-09-08T21:00:00Z | delivered_late | 70 | 0 |
| O0089 | Eastgate | express | R21 | 2026-09-09T06:00:00Z | 2026-09-09T14:00:00Z | on_time | 0 | 0 |
| O0090 | Eastgate | express | R22 | 2026-09-10T07:00:00Z | 2026-09-10T15:00:00Z | delivered_late | 70 | 0 |
| O0091 | Eastgate | express | R21 | 2026-09-11T08:00:00Z | 2026-09-11T16:00:00Z | delivered_late | 70 | 0 |
| O0092 | Eastgate | express | R22 | 2026-09-12T09:00:00Z | 2026-09-12T17:00:00Z | on_time | 0 | 0 |
| O0093 | Eastgate | express | R21 | 2026-09-13T10:00:00Z | 2026-09-13T18:00:00Z | delivered_late | 70 | 0 |
| O0094 | Eastgate | express | R22 | 2026-09-01T11:00:00Z | 2026-09-01T19:00:00Z | delivered_late | 70 | 0 |
| O0095 | Eastgate | express | R21 | 2026-09-02T12:00:00Z | 2026-09-02T20:00:00Z | on_time | 0 | 0 |
| O0096 | Eastgate | express | R22 | 2026-09-03T13:00:00Z | 2026-09-03T21:00:00Z | delivered_late | 70 | 0 |
| O0097 | Eastgate | express | R21 | 2026-09-04T06:00:00Z | 2026-09-04T14:00:00Z | delivered_late | 70 | 0 |
| O0098 | Eastgate | express | R22 | 2026-09-05T07:00:00Z | 2026-09-05T15:00:00Z | overdue_open | 0 | 13500 |
| O0099 | Eastgate | express | R21 | 2026-09-06T08:00:00Z | 2026-09-06T16:00:00Z | delivered_late | 70 | 0 |
| O0100 | Eastgate | express | R22 | 2026-09-07T09:00:00Z | 2026-09-07T17:00:00Z | delivered_late | 70 | 0 |
| O0101 | Eastgate | express | R21 | 2026-09-08T10:00:00Z | 2026-09-08T18:00:00Z | on_time | 0 | 0 |
| O0102 | Eastgate | express | R22 | 2026-09-09T11:00:00Z | 2026-09-09T19:00:00Z | delivered_late | 70 | 0 |
| O0103 | Eastgate | express | R21 | 2026-09-10T12:00:00Z | 2026-09-10T20:00:00Z | delivered_late | 70 | 0 |
| O0104 | Eastgate | express | R22 | 2026-09-11T13:00:00Z | 2026-09-11T21:00:00Z | on_time | 0 | 0 |
| O0105 | Eastgate | express | R21 | 2026-09-12T06:00:00Z | 2026-09-12T14:00:00Z | delivered_late | 70 | 0 |
| O0106 | Eastgate | express | R22 | 2026-09-13T07:00:00Z | 2026-09-13T15:00:00Z | delivered_late | 70 | 0 |
| O0107 | Eastgate | express | R21 | 2026-09-01T08:00:00Z | 2026-09-01T16:00:00Z | on_time | 0 | 0 |
| O0108 | Eastgate | express | R22 | 2026-09-02T09:00:00Z | 2026-09-02T17:00:00Z | delivered_late | 70 | 0 |
| O0109 | Eastgate | express | R21 | 2026-09-03T10:00:00Z | 2026-09-03T18:00:00Z | delivered_late | 70 | 0 |
| O0110 | Eastgate | express | R22 | 2026-09-04T11:00:00Z | 2026-09-04T19:00:00Z | cancelled | 0 | 0 |
| O0111 | Eastgate | express | R21 | 2026-09-05T12:00:00Z | 2026-09-05T20:00:00Z | delivered_late | 70 | 0 |
| O0112 | Eastgate | express | R22 | 2026-09-06T13:00:00Z | 2026-09-06T21:00:00Z | delivered_late | 70 | 0 |
| O0113 | Eastgate | express | R21 | 2026-09-07T06:00:00Z | 2026-09-07T14:00:00Z | on_time | 0 | 0 |
| O0114 | Eastgate | express | R22 | 2026-09-08T07:00:00Z | 2026-09-08T15:00:00Z | delivered_late | 70 | 0 |
| O0115 | Eastgate | express | R21 | 2026-09-09T08:00:00Z | 2026-09-09T16:00:00Z | overdue_open | 0 | 7680 |
| O0116 | Eastgate | express | R22 | 2026-09-10T09:00:00Z | 2026-09-10T17:00:00Z | on_time | 0 | 0 |
| O0117 | Eastgate | express | R21 | 2026-09-11T10:00:00Z | 2026-09-11T18:00:00Z | delivered_late | 70 | 0 |
| O0118 | Eastgate | express | R22 | 2026-09-12T11:00:00Z | 2026-09-12T19:00:00Z | delivered_late | 70 | 0 |
| O0119 | Eastgate | express | R21 | 2026-09-13T12:00:00Z | 2026-09-13T20:00:00Z | on_time | 0 | 0 |
| O0120 | Eastgate | express | R22 | 2026-09-14T21:00:00Z | 2026-09-15T05:00:00Z | not_mature | 0 | 0 |
| O0121 | Westhill | standard | R31 | 2026-09-01T06:00:00Z | 2026-09-02T06:00:00Z | cancelled | 0 | 0 |
| O0122 | Westhill | standard | R32 | 2026-09-02T07:00:00Z | 2026-09-03T07:00:00Z | delivered_late | 90 | 0 |
| O0123 | Westhill | standard | R31 | 2026-09-03T08:00:00Z | 2026-09-04T08:00:00Z | on_time | 0 | 0 |
| O0124 | Westhill | standard | R32 | 2026-09-04T09:00:00Z | 2026-09-05T09:00:00Z | on_time | 0 | 0 |
| O0125 | Westhill | standard | R31 | 2026-09-05T10:00:00Z | 2026-09-06T10:00:00Z | on_time | 0 | 0 |
| O0126 | Westhill | standard | R32 | 2026-09-06T11:00:00Z | 2026-09-07T11:00:00Z | on_time | 0 | 0 |
| O0127 | Westhill | standard | R31 | 2026-09-07T12:00:00Z | 2026-09-08T12:00:00Z | delivered_late | 90 | 0 |
| O0128 | Westhill | standard | R32 | 2026-09-08T13:00:00Z | 2026-09-09T13:00:00Z | on_time | 0 | 0 |
| O0129 | Westhill | standard | R31 | 2026-09-09T06:00:00Z | 2026-09-10T06:00:00Z | on_time | 0 | 0 |
| O0130 | Westhill | standard | R32 | 2026-09-10T07:00:00Z | 2026-09-11T07:00:00Z | on_time | 0 | 0 |
| O0131 | Westhill | standard | R31 | 2026-09-11T08:00:00Z | 2026-09-12T08:00:00Z | on_time | 0 | 0 |
| O0132 | Westhill | standard | R32 | 2026-09-12T09:00:00Z | 2026-09-13T09:00:00Z | delivered_late | 90 | 0 |
| O0133 | Westhill | standard | R31 | 2026-09-13T10:00:00Z | 2026-09-14T10:00:00Z | on_time | 0 | 0 |
| O0134 | Westhill | standard | R32 | 2026-09-01T11:00:00Z | 2026-09-02T11:00:00Z | on_time | 0 | 0 |
| O0135 | Westhill | standard | R31 | 2026-09-02T12:00:00Z | 2026-09-03T12:00:00Z | on_time | 0 | 0 |
| O0136 | Westhill | standard | R32 | 2026-09-03T13:00:00Z | 2026-09-04T13:00:00Z | on_time | 0 | 0 |
| O0137 | Westhill | standard | R31 | 2026-09-04T06:00:00Z | 2026-09-05T06:00:00Z | delivered_late | 90 | 0 |
| O0138 | Westhill | standard | R32 | 2026-09-05T07:00:00Z | 2026-09-06T07:00:00Z | overdue_open | 0 | 12540 |
| O0139 | Westhill | standard | R31 | 2026-09-06T08:00:00Z | 2026-09-07T08:00:00Z | on_time | 0 | 0 |
| O0140 | Westhill | standard | R32 | 2026-09-07T09:00:00Z | 2026-09-08T09:00:00Z | on_time | 0 | 0 |
| O0141 | Westhill | standard | R31 | 2026-09-08T10:00:00Z | 2026-09-09T10:00:00Z | on_time | 0 | 0 |
| O0142 | Westhill | standard | R32 | 2026-09-09T11:00:00Z | 2026-09-10T11:00:00Z | delivered_late | 90 | 0 |
| O0143 | Westhill | standard | R31 | 2026-09-10T12:00:00Z | 2026-09-11T12:00:00Z | on_time | 0 | 0 |
| O0144 | Westhill | standard | R32 | 2026-09-11T13:00:00Z | 2026-09-12T13:00:00Z | on_time | 0 | 0 |
| O0145 | Westhill | standard | R31 | 2026-09-12T06:00:00Z | 2026-09-13T06:00:00Z | on_time | 0 | 0 |
| O0146 | Westhill | standard | R32 | 2026-09-13T07:00:00Z | 2026-09-14T07:00:00Z | on_time | 0 | 0 |
| O0147 | Westhill | standard | R31 | 2026-09-01T08:00:00Z | 2026-09-02T08:00:00Z | delivered_late | 90 | 0 |
| O0148 | Westhill | standard | R32 | 2026-09-02T09:00:00Z | 2026-09-03T09:00:00Z | on_time | 0 | 0 |
| O0149 | Westhill | standard | R31 | 2026-09-03T10:00:00Z | 2026-09-04T10:00:00Z | on_time | 0 | 0 |
| O0150 | Westhill | standard | R32 | 2026-09-04T11:00:00Z | 2026-09-05T11:00:00Z | cancelled | 0 | 0 |
| O0151 | Westhill | standard | R31 | 2026-09-05T12:00:00Z | 2026-09-06T12:00:00Z | on_time | 0 | 0 |
| O0152 | Westhill | standard | R32 | 2026-09-06T13:00:00Z | 2026-09-07T13:00:00Z | delivered_late | 90 | 0 |
| O0153 | Westhill | standard | R31 | 2026-09-07T06:00:00Z | 2026-09-08T06:00:00Z | on_time | 0 | 0 |
| O0154 | Westhill | standard | R32 | 2026-09-08T07:00:00Z | 2026-09-09T07:00:00Z | on_time | 0 | 0 |
| O0155 | Westhill | standard | R31 | 2026-09-09T08:00:00Z | 2026-09-10T08:00:00Z | overdue_open | 0 | 6720 |
| O0156 | Westhill | standard | R32 | 2026-09-14T21:00:00Z | 2026-09-15T21:00:00Z | not_mature | 0 | 0 |
| O0157 | Westhill | express | R31 | 2026-09-01T06:00:00Z | 2026-09-01T14:00:00Z | cancelled | 0 | 0 |
| O0158 | Westhill | express | R32 | 2026-09-02T07:00:00Z | 2026-09-02T15:00:00Z | delivered_late | 90 | 0 |
| O0159 | Westhill | express | R31 | 2026-09-03T08:00:00Z | 2026-09-03T16:00:00Z | on_time | 0 | 0 |
| O0160 | Westhill | express | R32 | 2026-09-04T09:00:00Z | 2026-09-04T17:00:00Z | on_time | 0 | 0 |
| O0161 | Westhill | express | R31 | 2026-09-05T10:00:00Z | 2026-09-05T18:00:00Z | delivered_late | 90 | 0 |
| O0162 | Westhill | express | R32 | 2026-09-06T11:00:00Z | 2026-09-06T19:00:00Z | delivered_late | 90 | 0 |
| O0163 | Westhill | express | R31 | 2026-09-07T12:00:00Z | 2026-09-07T20:00:00Z | on_time | 0 | 0 |
| O0164 | Westhill | express | R32 | 2026-09-08T13:00:00Z | 2026-09-08T21:00:00Z | on_time | 0 | 0 |
| O0165 | Westhill | express | R31 | 2026-09-09T06:00:00Z | 2026-09-09T14:00:00Z | delivered_late | 90 | 0 |
| O0166 | Westhill | express | R32 | 2026-09-10T07:00:00Z | 2026-09-10T15:00:00Z | delivered_late | 90 | 0 |
| O0167 | Westhill | express | R31 | 2026-09-11T08:00:00Z | 2026-09-11T16:00:00Z | on_time | 0 | 0 |
| O0168 | Westhill | express | R32 | 2026-09-12T09:00:00Z | 2026-09-12T17:00:00Z | on_time | 0 | 0 |
| O0169 | Westhill | express | R31 | 2026-09-13T10:00:00Z | 2026-09-13T18:00:00Z | delivered_late | 90 | 0 |
| O0170 | Westhill | express | R32 | 2026-09-01T11:00:00Z | 2026-09-01T19:00:00Z | delivered_late | 90 | 0 |
| O0171 | Westhill | express | R31 | 2026-09-02T12:00:00Z | 2026-09-02T20:00:00Z | on_time | 0 | 0 |
| O0172 | Westhill | express | R32 | 2026-09-03T13:00:00Z | 2026-09-03T21:00:00Z | on_time | 0 | 0 |
| O0173 | Westhill | express | R31 | 2026-09-04T06:00:00Z | 2026-09-04T14:00:00Z | delivered_late | 90 | 0 |
| O0174 | Westhill | express | R32 | 2026-09-05T07:00:00Z | 2026-09-05T15:00:00Z | overdue_open | 0 | 13500 |
| O0175 | Westhill | express | R31 | 2026-09-06T08:00:00Z | 2026-09-06T16:00:00Z | on_time | 0 | 0 |
| O0176 | Westhill | express | R32 | 2026-09-07T09:00:00Z | 2026-09-07T17:00:00Z | on_time | 0 | 0 |
| O0177 | Westhill | express | R31 | 2026-09-08T10:00:00Z | 2026-09-08T18:00:00Z | delivered_late | 90 | 0 |
| O0178 | Westhill | express | R32 | 2026-09-09T11:00:00Z | 2026-09-09T19:00:00Z | delivered_late | 90 | 0 |
| O0179 | Westhill | express | R31 | 2026-09-10T12:00:00Z | 2026-09-10T20:00:00Z | on_time | 0 | 0 |
| O0180 | Westhill | express | R32 | 2026-09-14T21:00:00Z | 2026-09-15T05:00:00Z | not_mature | 0 | 0 |
| O0181 | Southbay | standard | R41 | 2026-09-01T06:00:00Z | 2026-09-02T06:00:00Z | cancelled | 0 | 0 |
| O0182 | Southbay | standard | R42 | 2026-09-02T07:00:00Z | 2026-09-03T07:00:00Z | delivered_late | 110 | 0 |
| O0183 | Southbay | standard | R41 | 2026-09-03T08:00:00Z | 2026-09-04T08:00:00Z | on_time | 0 | 0 |
| O0184 | Southbay | standard | R42 | 2026-09-04T09:00:00Z | 2026-09-05T09:00:00Z | on_time | 0 | 0 |
| O0185 | Southbay | standard | R41 | 2026-09-05T10:00:00Z | 2026-09-06T10:00:00Z | on_time | 0 | 0 |
| O0186 | Southbay | standard | R42 | 2026-09-06T11:00:00Z | 2026-09-07T11:00:00Z | on_time | 0 | 0 |
| O0187 | Southbay | standard | R41 | 2026-09-07T12:00:00Z | 2026-09-08T12:00:00Z | on_time | 0 | 0 |
| O0188 | Southbay | standard | R42 | 2026-09-08T13:00:00Z | 2026-09-09T13:00:00Z | delivered_late | 110 | 0 |
| O0189 | Southbay | standard | R41 | 2026-09-09T06:00:00Z | 2026-09-10T06:00:00Z | on_time | 0 | 0 |
| O0190 | Southbay | standard | R42 | 2026-09-10T07:00:00Z | 2026-09-11T07:00:00Z | on_time | 0 | 0 |
| O0191 | Southbay | standard | R41 | 2026-09-11T08:00:00Z | 2026-09-12T08:00:00Z | on_time | 0 | 0 |
| O0192 | Southbay | standard | R42 | 2026-09-12T09:00:00Z | 2026-09-13T09:00:00Z | on_time | 0 | 0 |
| O0193 | Southbay | standard | R41 | 2026-09-13T10:00:00Z | 2026-09-14T10:00:00Z | on_time | 0 | 0 |
| O0194 | Southbay | standard | R42 | 2026-09-01T11:00:00Z | 2026-09-02T11:00:00Z | delivered_late | 110 | 0 |
| O0195 | Southbay | standard | R41 | 2026-09-02T12:00:00Z | 2026-09-03T12:00:00Z | on_time | 0 | 0 |
| O0196 | Southbay | standard | R42 | 2026-09-03T13:00:00Z | 2026-09-04T13:00:00Z | on_time | 0 | 0 |
| O0197 | Southbay | standard | R41 | 2026-09-04T06:00:00Z | 2026-09-05T06:00:00Z | on_time | 0 | 0 |
| O0198 | Southbay | standard | R42 | 2026-09-05T07:00:00Z | 2026-09-06T07:00:00Z | overdue_open | 0 | 12540 |
| O0199 | Southbay | standard | R41 | 2026-09-06T08:00:00Z | 2026-09-07T08:00:00Z | on_time | 0 | 0 |
| O0200 | Southbay | standard | R42 | 2026-09-07T09:00:00Z | 2026-09-08T09:00:00Z | delivered_late | 110 | 0 |
| O0201 | Southbay | standard | R41 | 2026-09-08T10:00:00Z | 2026-09-09T10:00:00Z | on_time | 0 | 0 |
| O0202 | Southbay | standard | R42 | 2026-09-09T11:00:00Z | 2026-09-10T11:00:00Z | on_time | 0 | 0 |
| O0203 | Southbay | standard | R41 | 2026-09-10T12:00:00Z | 2026-09-11T12:00:00Z | on_time | 0 | 0 |
| O0204 | Southbay | standard | R42 | 2026-09-11T13:00:00Z | 2026-09-12T13:00:00Z | on_time | 0 | 0 |
| O0205 | Southbay | standard | R41 | 2026-09-12T06:00:00Z | 2026-09-13T06:00:00Z | on_time | 0 | 0 |
| O0206 | Southbay | standard | R42 | 2026-09-13T07:00:00Z | 2026-09-14T07:00:00Z | delivered_late | 110 | 0 |
| O0207 | Southbay | standard | R41 | 2026-09-01T08:00:00Z | 2026-09-02T08:00:00Z | on_time | 0 | 0 |
| O0208 | Southbay | standard | R42 | 2026-09-02T09:00:00Z | 2026-09-03T09:00:00Z | on_time | 0 | 0 |
| O0209 | Southbay | standard | R41 | 2026-09-03T10:00:00Z | 2026-09-04T10:00:00Z | on_time | 0 | 0 |
| O0210 | Southbay | standard | R42 | 2026-09-14T21:00:00Z | 2026-09-15T21:00:00Z | cancelled | 0 | 0 |
| O0211 | Southbay | express | R41 | 2026-09-01T06:00:00Z | 2026-09-01T14:00:00Z | cancelled | 0 | 0 |
| O0212 | Southbay | express | R42 | 2026-09-02T07:00:00Z | 2026-09-02T15:00:00Z | delivered_late | 110 | 0 |
| O0213 | Southbay | express | R41 | 2026-09-03T08:00:00Z | 2026-09-03T16:00:00Z | on_time | 0 | 0 |
| O0214 | Southbay | express | R42 | 2026-09-04T09:00:00Z | 2026-09-04T17:00:00Z | on_time | 0 | 0 |
| O0215 | Southbay | express | R41 | 2026-09-05T10:00:00Z | 2026-09-05T18:00:00Z | on_time | 0 | 0 |
| O0216 | Southbay | express | R42 | 2026-09-14T21:00:00Z | 2026-09-15T05:00:00Z | not_mature | 0 | 0 |
learner/checkpoints/hub-metrics.csv Read the full file
Download file| hub | total | eligible | late | late_rate | on_time | delivered_late | overdue_open | cancelled | not_mature | delivered_late_minutes | open_overdue_minutes |
|---|---|---|---|---|---|---|---|---|---|---|---|
| Eastgate | 60 | 55 | 31 | 0.563636 | 24 | 28 | 3 | 3 | 2 | 1960 | 33720 |
| Harbour | 60 | 55 | 32 | 0.581818 | 23 | 29 | 3 | 3 | 2 | 1450 | 32760 |
| Southbay | 36 | 32 | 7 | 0.21875 | 25 | 6 | 1 | 3 | 1 | 660 | 12540 |
| Westhill | 60 | 55 | 20 | 0.363636 | 35 | 17 | 3 | 3 | 2 | 1530 | 32760 |
learner/checkpoints/service-review.csv Read the full file
Download file| hub | service | eligible | late | late_rate | target | gap_pp | review |
|---|---|---|---|---|---|---|---|
| Eastgate | express | 37 | 26 | 0.702703 | 0.1 | 60.27 | Priority review |
| Eastgate | standard | 18 | 5 | 0.277778 | 0.1 | 17.778 | Priority review |
| Harbour | express | 18 | 18 | 1.0 | 0.1 | 90.0 | Priority review |
| Harbour | standard | 37 | 14 | 0.378378 | 0.1 | 27.838 | Priority review |
| Southbay | express | 4 | 1 | 0.25 | 0.1 | 15.0 | More data needed |
| Southbay | standard | 28 | 6 | 0.214286 | 0.1 | 11.429 | Review needed |
| Westhill | express | 22 | 11 | 0.5 | 0.1 | 40.0 | Priority review |
| Westhill | standard | 33 | 9 | 0.272727 | 0.1 | 17.273 | Priority review |
learner/materials/access-policy.json Read the full file
Download file{
"session_ttl_minutes": 30,
"export_roles": [
"supervisor",
"service"
],
"operator_hub": {
"op-1": "Harbour",
"op-2": "Eastgate",
"op-3": "Westhill",
"op-4": "Southbay",
"op-7": "Harbour"
},
"network_note": "Access is through a corporate VPN gateway. Documentation IP addresses do not establish location or personal identity.",
"service_accounts": [
"svc-archive"
]
}Steps
- Extract stakeholder requirements and connect them to the findings in tasks two, three and four. Define users, primary decisions and explicit phase-one exclusions.
- Design hub summary → order list → event timeline. Implement hub, service and cohort filters, evidence expansion and an empty-results reset.
- Specify pagination, filters, as_of, dataset version, authorization and 401/403/503 behavior. Corporate authentication is a dependency; hiding a control is not server authorization.
- Map R1–R6 to UI behavior, APIs and acceptance cases. Include future events, cancellation, insufficient samples, no results, expired sessions and data delay.
- Break down design, data, frontend, API, integration, testing and handover effort. Reconcile person-hours to weekly capacity and make client access and approval dependencies explicit.
- Deliver proposal.md, api-contract.json and requirements-traceability.csv with the usable workbench. Include architecture, acceptance, milestones, support, rollback and open decisions.
Complete outputs
Cold-chain operations workbench delivery proposal
1. Purpose, users and scope
Operations staff need to act on undelivered overdue orders and trace the underlying evidence. Hub leads need service-stratified metrics. Security staff need dependable session and export controls. Phase one delivers a read-only workbench, metrics API, order timeline and controlled export design. Refunds, dispatch writes, customer notifications and employee rankings are excluded.
R1: filter by hub, service and cohort, prioritizing overdue_open. R2: open complete order evidence with the review cutoff; future events cannot alter a historical metric. R3: exclude cancelled and not-mature orders from the mature denominator. R4: show stratified rates and sample limitations. R5: enforce role, hub and session permissions on the server. R6: provide loading, no-results, errors, freshness and recovery states.
2. Information structure and interaction
Start with cutoff, mature count, late count and open overdue count, followed by hub rates and the order queue. Combine the three filters with AND. Keep the result count and displayed orders in sync. Expand an order to show created, picked_up, delivered or cancelled events, including whether an event is later than the cutoff. No matches displays a clear message and a reset action.
The completed reference workbench supports all 216 orders and their full timelines. For production integration, prevent duplicate requests during loading; update the last-success timestamp on completion. On 503, retain the last successful version with a visible error. On session expiry, clear sensitive views and return to corporate login. The reference interaction does not implement a production identity service or export permission system; those are acceptance items below.
3. Architecture and data flow
Feed A/B → schema validation and conflict quarantine → immutable canonical event store → order view aggregated at as_of → intranet read-only API → workbench. The orders master supplies route and due_at; visible events determine status. Store dataset_version, ingested_at and source_line for reconciliation and replay. A failed incoming batch must not replace the previous reconciled snapshot.
The corporate identity service issues sessions. The gateway validates sessions and each API checks role plus hub scope. A requested hub is not authorization. Operators access only assigned hubs. Supervisors and batch-scoped service accounts can export within their grants. No application password store is added. Export audit records request_id, user, scope, rows, bytes and dataset_version, without secrets.
4. API contract
GET /v1/orders?hub=&service=&cohort=&as_of=&cursor=&limit=50 returns items, next_cursor, total, as_of, dataset_version and updated_at. Limit is 1–100. Use a stable server cursor and the same snapshot for a page sequence to avoid missing or duplicate orders. Invalid filters return 400; a valid empty query returns 200 with an empty items list.
GET /v1/orders/{order_id}/events?as_of= returns ordered events and visible_at_cutoff. Check access before returning content. Missing orders return 404 and forbidden access returns 403. GET /v1/metrics returns mature and late counts, hub/service strata and insufficient-sample states for the same snapshot.
POST /v1/exports requires supervisor or service permission. The body includes scope, as_of, dataset_version and request_key. Accept a job with 202 and job_id, then authorize the completed download against the same scope. Operators receive 403. Deduplicate request_key on the server and audit each export batch.
Errors are 400 for input, 401 for missing/expired session, 403 for permission, 404 for absent resources, 409 for snapshot mismatch, 429 for throttling and 503 for source failure. Include request_id and a safe explanation without credentials.
5. Acceptance and traceability
R1: Harbour + express + overdue_open shows one matching order, O0058, and resetting restores 216. R2: every timeline matches the canonical records and future delivery does not alter the historical cohort. R3: 216 = 12 cancelled + 7 not_mature + 107 on_time + 80 delivered_late + 10 overdue_open, with mature 197 and late 90. R4: Southbay express n=4 requires more data and has no standardized hub value; check 5/15-point boundaries. R5: operator export 403, expired session 401 and authorized supervisor export 202; selecting another hub still returns 403 for an operator. R6: test empty results, loading, 503 retained snapshots, 429 retry and successful recovery timestamps.
requirements-traceability.csv links every requirement to an API and a test. Reference UI and algorithm checks verify the learning output. Production permissions, network failures, pagination and load acceptance require the integrated backend; a working static page is not that evidence.
6. Effort and milestones
| Workstream | Person-hours | Acceptance gate |
|---|---|---|
| Requirements, metric rules and interaction design | 16 | R1–R6, identity and source contracts agreed |
| Ingestion, aggregation and snapshots | 28 | Reconciliation, replay and future-event tests |
| Frontend and accessibility | 24 | Filters, timelines, empty results and keyboard use |
| API, permissions and export audit | 24 | Session, scope and export checks |
| Identity/gateway integration and release readiness | 16 | Client interfaces, rollback and monitoring |
| Integration, security and user acceptance tests | 24 | All requirements pass and findings are resolved |
| Runbook and handover | 8 | Operations and recovery rehearsal |
| Total | 140 | Dependent on access and approvals |
Plan one engineer at 35 delivery hours per week for four working weeks. Week 1: design 16 + data 19. Week 2: data 9 + frontend 24 + API 2. Week 3: API 22 + integration 13. Week 4: integration 3 + testing 24 + handover 8. Each week totals 35, and the workstreams total 140. Client approval and access waiting time are outside this effort. Delayed security review moves calendar milestones rather than removing tests. Capacity and skills are planning assumptions to confirm, not an agreed production launch or price.
7. Operations, support and rollback
Monitor quarantine rates, snapshot age, API errors, access denials and export volumes. Support tickets include hub impact, request_id, data version and reproduction steps. A technical duty owner triages access failures and an operations owner confirms business impact. Support hours, response targets, retention and charges require agreement before launch.
Rollback reads to the last reconciled snapshot while retaining source and quarantine records. Retain access checks even if an API version is reverted. After recovery, recompute the 197/90 controls for the reference snapshot, compare versions and obtain operations sign-off. Rehearse backup and restore before release.
8. Dependencies and decisions
The client provides identity protocols, role/hub grants, gateway access, source interfaces and retention requirements. Confirm concurrency, arrival delay, refresh interval, export limits, audit retention and support coverage in week one. Record-based acceptance here does not establish production traffic capacity or an improvement in actual fulfilment outcomes.
Download fileOpen complete workbenchReference answers
instructor/answers/api-contract.json Read the full file
Download file{
"version": "1.0",
"as_of": "2026-09-15T00:00:00Z",
"dataset_version": "coldchain-v1",
"routes": [
{
"method": "GET",
"path": "/v1/orders",
"query": [
"hub",
"service",
"cohort",
"as_of",
"cursor",
"limit"
],
"limit": {
"min": 1,
"max": 100
},
"response": [
"items",
"total",
"next_cursor",
"as_of",
"dataset_version",
"updated_at"
],
"errors": [
400,
401,
403,
409,
429,
503
]
},
{
"method": "GET",
"path": "/v1/orders/{order_id}/events",
"response": [
"events",
"visible_at_cutoff"
],
"errors": [
401,
403,
404,
503
]
},
{
"method": "GET",
"path": "/v1/metrics",
"response": [
"eligible",
"late",
"by_hub",
"by_service",
"sample_status"
],
"errors": [
400,
401,
403,
409,
503
]
},
{
"method": "POST",
"path": "/v1/exports",
"roles": [
"supervisor",
"service"
],
"body": [
"scope",
"as_of",
"dataset_version",
"request_key"
],
"accepted_status": 202,
"errors": [
400,
401,
403,
409,
429,
503
]
}
]
}
instructor/answers/requirements-traceability.csv Read the full file
Download file| requirement | outcome | endpoint | test | verification |
|---|---|---|---|---|
| R1 | Combined filters and open-overdue priority | GET /v1/orders | Harbour + express + overdue_open gives O0058; reset to 216 | Reference interaction available; production pagination requires integration |
| R2 | Event traceability and historical cutoff | GET /v1/orders/{id}/events | Future delivery cannot change the historical cohort | Timeline and algorithm tests |
| R3 | Mature-order metric denominator | GET /v1/metrics | 197 mature, 90 late | Complete recalculation and independent counts |
| R4 | Small samples and service mix | GET /v1/metrics | Southbay express n=4; standardized hub rate missing | Calculation and boundary tests |
| R5 | Authorization and session expiry | POST /v1/exports | operator 403; expired session 401; authorized export 202 | Contract and investigation tests; production backend integration required |
| R6 | Empty results and error recovery | All APIs | Reset empty results; retain snapshot on 503; retry 429 | Empty-state interaction available; network cases require integration |
Complete reference implementation Read the full file
Download 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.
- Evidence-to-requirement traceability: 5
- Architecture and authorization boundaries: 5
- Consistent estimates and dependencies: 5
- Complete proposal and usable output: 5