Prototype: MessageQueue publishes each lifetime ID once (even after consumption); consume removes oldest Message or returns null. Empty IDs/payloads are valid.
Final: MessageBroker(maxAttempts) requires >=1. Retain immutable messages in FIFO order; duplicate publish preserves payload. subscribe starts at the oldest log entry and duplicate subscribe preserves progress. poll returns Delivery(id,payload,attempt), repeats an in-flight attempt unchanged, and increments only on redelivery after retry. ack accepts only matching current in-flight ID and advances/reset attempts. nack returns null for invalid, retry below limit without advancing, or dead-letter at limit and appends DeadLetter(id,payload,attempts) then advances. Groups are independent; unknown polls are null, unknown DLQs empty. deadLetters is a fresh nondraining list.
The complete public API is in Exercise.java. All domain classes are public static nested classes of Exercise; construct them as new Exercise.ClassName(...). Do not implement a solution in the test runner. Each instance owns independent state. Unless explicitly allowed, null inputs are outside the domain. Failed operations leave state unchanged; validation happens before mutation.
Complete the starter code, then run the checks.
Results and errors will appear here.
Java runs on this device with CheerpJ 4.3.