cswork / libraryOpen practice workspace

Coding questions · Vanta

Design streaming test logger and queries

This question evaluates a candidate's ability to design streaming data structures and time-series algorithms to track state transitions and compute interval queries, covering competencies in online/event-processing algorithms, interval overlap aggregation, and algorithmic complexity analysis within the Coding & Algorithms domain.

Implement a streaming logger and two query operations for test runs with globally strictly increasing timestamps.

  1. Implement log(test_id, timestamp, status) where status ∈ {'failing','passing'}.
  2. Implement get_min_fix_time(test_id) -> number|null: For the specified test, return the minimal duration from the start of a failing state to the next subsequent passing state. If multiple failing statuses occur consecutively, treat them as a single failure starting at the first failure; if the failure never resolves to passing, or the test never fails, return null.
  3. Implement get_max_concurrent_failure_period(min_tests) -> {start_timestamp, end_timestamp}|null: Return the longest contiguous period [start_timestamp, end_timestamp) during which at least min_tests distinct tests are failing simultaneously; if no such period exists, return null. Assume timestamps are integers and strictly increasing across all log calls. Describe your data structures, algorithms, and time/space complexities.

Part 1: Build normalized failure intervals from log()

You are given a chronologically ordered stream of log events (test_id, timestamp, status), where status is either 'failing' or 'passing' and timestamps are globally strictly increasing. Process the stream as if log(test_id, timestamp, status) were called for each event. For every test ID that appears in the stream, return its normalized failure intervals. A failure interval starts at the first 'failing' event in a consecutive failing streak and ends at the next later 'passing' event for the same test. Consecutive 'failing' events while the test is already failing do not start new intervals. Consecutive 'passing' events while the test is not failing do nothing. If a failure is still open at the end of the stream, its end should be None.

Constraints

  • 0 <= len(logs) <= 200000
  • Each log entry is (test_id, timestamp, status)
  • Timestamps are integers and strictly increasing across the entire stream
  • status is always either 'failing' or 'passing'

Examples

Example 1

Input: ([('T1', 1, 'failing'), ('T1', 4, 'passing')],)
Output: {'T1': [(1, 4)]}

Explanation: A single failing streak starts at 1 and resolves at 4.

Example 2

Input: ([('T1', 1, 'failing'), ('T1', 2, 'failing'), ('T1', 5, 'passing'), ('T1', 8, 'failing')],)
Output: {'T1': [(1, 5), (8, None)]}

Explanation: The first two failing logs are one streak. The final failure is unresolved.

Hints

  1. Track, for each test, whether a failure is currently open and when it started.
  2. A 'failing' log only matters if the test was not already failing; a 'passing' log only matters if it was.

Part 2: Minimum fix time for one test

You are given a chronologically ordered stream of log events (test_id, timestamp, status) and a target test_id. For that one test, compute the minimum time needed to recover from failure. A failure starts at the first 'failing' event in a consecutive failing streak and ends at the next later 'passing' event for the same test. Consecutive 'failing' logs while already failing belong to the same failure. If the test never has a resolved failure, return None.

Constraints

  • 0 <= len(logs) <= 200000
  • Each log entry is (test_id, timestamp, status)
  • Timestamps are integers and strictly increasing across the entire stream
  • status is always either 'failing' or 'passing'

Examples

Example 1

Input: ([('A', 1, 'failing'), ('A', 3, 'passing'), ('A', 5, 'failing'), ('A', 9, 'passing')], 'A')
Output: 2

Explanation: Resolved failure lengths are 2 and 4, so the minimum is 2.

Example 2

Input: ([('A', 1, 'failing'), ('B', 2, 'failing'), ('A', 4, 'failing'), ('A', 6, 'passing'), ('B', 8, 'passing'), ('A', 10, 'failing'), ('A', 12, 'passing')], 'A')
Output: 2

Explanation: For A, the streak from 1 to 6 has length 5 because the extra failing at 4 does not restart it. The second resolved streak has length 2.

Hints

  1. You only need to track the current open failure for the queried test, not for every test.
  2. Ignore consecutive 'failing' logs until you see a 'passing' log that closes the active failure.

Part 3: Longest period with at least k concurrent failing tests

You are given a chronologically ordered stream of log events (test_id, timestamp, status) and an integer min_tests. A test is considered failing from the first 'failing' log in a failing streak until the next 'passing' log for that same test. Consecutive 'failing' logs while already failing do not change the state, and consecutive 'passing' logs while not failing do nothing. After processing a log at timestamp t_i, the resulting failure set is stable on the half-open segment [t_i, t_{i+1}), where t_{i+1} is the next log timestamp. Return the longest contiguous period [start_timestamp, end_timestamp) during which at least min_tests distinct tests are failing simultaneously on every point of the period. If multiple periods have the same maximum length, return the earliest one. If no such finite period exists, return None.

Constraints

  • 0 <= len(logs) <= 200000
  • Each log entry is (test_id, timestamp, status)
  • Timestamps are integers and strictly increasing across the entire stream
  • status is always either 'failing' or 'passing'
  • 1 <= min_tests <= 200000

Examples

Example 1

Input: ([('A', 1, 'failing'), ('B', 2, 'failing'), ('A', 5, 'passing'), ('B', 7, 'passing')], 2)
Output: {'start_timestamp': 2, 'end_timestamp': 5}

Explanation: A fails on [1, 5), B fails on [2, 7), so both are failing together on [2, 5).

Example 2

Input: ([('A', 1, 'failing'), ('A', 2, 'failing'), ('B', 3, 'failing'), ('C', 4, 'failing'), ('B', 6, 'passing'), ('A', 8, 'passing'), ('C', 10, 'passing')], 2)
Output: {'start_timestamp': 3, 'end_timestamp': 8}

Explanation: At least two tests are failing continuously from 3 to 8. The extra failing log for A at 2 does not create a new interval.

Hints

  1. The number of failing tests can only change at log timestamps, so scan the stream segment by segment between consecutive timestamps.
  2. Maintain the current set of failing tests and the start of the current qualifying window where the failing count is at least min_tests.