Debug and Extend a Device Registry: Status Validation, Active Counts, Bulk Updates
Company: Onepay
Role: Software Engineer
Category: Software Engineering Fundamentals
Difficulty: medium
Interview Round: Technical Screen
You are handed a small existing Python module that manages a registry of devices, together with its tests. The exercise has several small steps that build on each other: read the existing code, use a failing test to find a bug, then add follow-up features. It is business-logic implementation rather than algorithm design, so clear structure, validation and tests matter more than clever data structures.
The original code was not shared. The module below is a representative reconstruction of the reported bug: a device may be stored only if its status is one that a configuration map allows for that device's type.
```python
ALLOWED_STATUSES = {
"sensor": {"ACTIVE", "INACTIVE", "MAINTENANCE"},
"camera": {"ACTIVE", "INACTIVE", "FAULTY"},
"gateway": {"ACTIVE", "MAINTENANCE", "FAULTY"},
}
class Device:
def __init__(self, device_id, device_type, status, registered_at):
self.device_id = device_id
self.device_type = device_type
self.status = status
self.registered_at = registered_at
self.last_maintenance_at = registered_at
self.failure_count = 0
class DeviceRegistry:
def __init__(self):
self.devices = {} # device_id -> Device
def is_valid_status(self, device_type, status):
for statuses in ALLOWED_STATUSES.values():
if status in statuses:
return True
return False
def add_device(self, device):
if not self.is_valid_status(device.device_type, device.status):
return False
self.devices[device.device_id] = device
return True
```
The failing test:
```python
def test_add_device_rejects_status_not_allowed_for_type():
registry = DeviceRegistry()
camera = Device("cam-1", "camera", "MAINTENANCE", 100)
assert registry.add_device(camera) is False
assert "cam-1" not in registry.devices
```
Assume other code, not shown, updates `last_maintenance_at` and `failure_count` as maintenance and failures are recorded.
### Clarifying Questions
- Should invalid input be reported by returning `False`, by raising an exception, or by returning an error that names the failed check?
- Are device types and statuses case-sensitive, and can the allowed-status map change while the registry is running?
- Is the registry used from more than one thread?
- Do callers or tests depend on any ordering of returned collections?
### Part 1 — Find and fix the bug
Explain why the test fails, fix the bug with a minimal change, and describe which other invalid inputs the same bug lets through.
```hint Follow the unused argument
Compare what `is_valid_status` does with its `device_type` argument with the way `ALLOWED_STATUSES` is keyed.
```
#### What This Part Should Cover
- The root cause, traced from the failing assertion back to the check
- A minimal fix and the other invalid inputs the defect accepted
- Regression tests for the fixed behavior
### Part 2 — Register a new device
Add `register_device(device_id, device_type, status, registered_at)`. At minimum it must reject a device ID that is already registered, a device type that is not in the map, a status that the map does not allow for that type, and a negative registration time. Otherwise it creates and stores the device. Decide what it returns or raises on each failure, and what else it should validate.
```hint A rejection leaves no trace
Think about the order of the checks so that a rejected call never modifies the registry, and about inputs that could raise inside your own validation before it reports anything.
```
#### Clarifying Questions for this Part
- Should a duplicate ID whose fields are identical to the stored device count as a harmless retry or as an error?
- Is the registration time an integer timestamp, and is a time in the future acceptable?
#### What This Part Should Cover
- Every reported check (duplicate ID, legal type, status allowed for the type, non-negative time) and the order they run in
- Atomicity: a rejected call leaves the registry unchanged
- An error-reporting contract that callers and tests can rely on
### Part 3 — Count active devices by type
Add `count_active_by_type()`, which returns a mapping from device type to the number of devices whose status is `ACTIVE`. A type with no active devices must not appear in the result.
```hint Where the keys come from
Decide whether to start from the list of known types or from the devices themselves, given that zero counts must be left out.
```
#### What This Part Should Cover
- Correct omission of types with zero active devices
- Time complexity, and whether maintaining live counters is worth it
- Deterministic output that tests can compare
### Part 4 — Bulk status update
Add a method that updates the status of every device that matches rules based on its last maintenance time and its failure count, and returns how many devices it updated. The exact thresholds, target statuses and precedence were not reported, so settle them through the clarifying questions below before implementing.
```hint Collisions between rules
Consider a device that matches both conditions, and a device whose target status is not allowed for its type by `ALLOWED_STATUSES`.
```
#### Clarifying Questions for this Part
- What are the thresholds (time since last maintenance, number of failures), and are they parameters or constants?
- Which status does each condition move a device to, and which condition wins when both apply?
- Does a device that is already in its target status count as updated?
- Which current statuses are eligible; for example, should an `INACTIVE` device be touched at all?
#### What This Part Should Cover
- Explicit, testable rules, including the precedence between the two conditions
- Respecting the allowed statuses per type during the update
- An updated count that includes only real changes
### What a Strong Answer Covers
- Reading the unfamiliar code and the test before editing anything
- One validation path reused by every write, so the original bug cannot reappear elsewhere
- Edge cases such as an empty registry, unknown types and repeated IDs
- Small, incremental changes, each backed by tests
- Business questions raised with the interviewer instead of silently guessed
### Follow-up Questions
- How would you make `register_device` safe if two threads register the same ID at the same moment?
- If the allowed-status map is loaded from configuration and a status is removed, what should happen to devices that currently hold it?
- How would you keep an audit history of status changes, including those made by the bulk update?
Overview: A progressive coding exercise on a device registry: find the bug behind a failing test where a device's status must be allowed for its type, then add validated registration, per-type counts of active devices that omit zeros, and a bulk status update based on maintenance time and failure count. It tests code reading and business logic.