Skip to content

Paging through messages

API / backend · Difficulty 3/5 · Python · 30 linesOrigin: Fictional

Task

What the AI was asked to do

Write the paging for the GET /conversations/<id>/messages endpoint: messages come newest first, one page at a time. Each page returns a next value that the client sends back for the following page, and scrolling must show every message exactly once. When there are no older messages, next is None. sent_at is UTC ISO 8601 text to the second, always in the same format. The caller has already checked that the user is a member of the conversation and that limit is between 1 and 100.

Handoff note

What the AI wrote when it handed over the code:

“Paging uses a cursor, so pages do not shift when new messages arrive. The order is made stable with id, the query is parameterized, and one extra row is read to detect the last page correctly.”

The code the AI wrote

Python30 lines

Mark the lines you think are wrong; give each mark a severity and a one-sentence reason.

Click or tap a line. With a keyboard, move to the line and press Enter.

0 of 5 marks
How to pick a severity
  • CriticalData loss, a security hole or lost money
  • MajorThe user gets a wrong result in a case the task asks for
  • MinorA rare edge case outside the task, or readability

In the Testing topic, severity is set by the effect of the broken implementation the test doesn't catch.

Your reason isn't graded; you'll compare it with a sample answer.

import sqlite3
2
SELECT = "SELECT id, sent_at, text FROM messages WHERE conversation_id = ?"
4
5
def list_messages(
    conn: sqlite3.Connection,
    conversation_id: int,
    limit: int,
    after: tuple[str, int] | None = None,
) -> dict:
    """GET /conversations/<id>/messages: newest first, one page at a time.
13
    `after` is the `next` value of the previous page (None on the first
    page). `next` is None when there are no older messages.
    """
    sql = SELECT
    params: list = [conversation_id]
    if after is not None:
        sql += " AND sent_at < ?"
        params.append(after[0])
    sql += " ORDER BY sent_at DESC, id DESC LIMIT ?"
    params.append(limit + 1)
    rows = conn.execute(sql, params).fetchall()
25
    page = rows[:limit]
    items = [{"id": r[0], "sent_at": r[1], "text": r[2]} for r in page]
    has_more = len(rows) > limit
    next_value = (page[-1][1], page[-1][0]) if has_more else None
    return {"items": items, "next": next_value}

The test that proves it

The right option is the test that fails on this code, which means it exposes the bug.

Test options
Mark at least one line to submit.

Submitting sends seven pieces of information to a counter; your reason text stays on your device. Data