Skip to content
MediumObservabilityPython 3

Agent Event Timeline

Build a reviewable append-only timeline for cloud-agent run events.

35m3 sample tests8 hidden tests

Implement EventTimeline, an append-only for agent runs. Two runs may interleave, so a pagination cursor must identify append order rather than depend on their clocks.

Requirements

  • append(run_id, kind, timestamp, message) stores an event and returns its sequence number.
  • Sequence numbers span all runs in one EventTimeline instance and start at 1. Each instance has its own counter.
  • list_events(run_id, after_seq=0, limit=100) returns events for one run with seq > after_seq.
  • Output events are dictionaries with seq, kind, timestamp, and message.
  • Messages must matching the exact pattern sk-[A-Za-z0-9_-]+: lowercase sk- followed by one or more ASCII letters, ASCII digits, underscores, or hyphens. Match substrings without requiring a word boundary.
  • Replace each match with the literal string [REDACTED].
  • Results are ordered by sequence and respect limit.
  • If limit <= 0, return an empty list.
  • Return fresh dictionaries so a caller can't change stored events by editing a listing. Inputs have the types shown in the starter code; no field validation or concurrent calls are required.

Example

Append one event per run, then ask for only the first run's events after its initial cursor:

timeline-examples.py
timeline = EventTimeline()
timeline.append("r1", "log", 1.0, "started")
assert timeline.list_events("r1")[0]["message"] == "started"
timeline.append("r2", "log", 2.0, "secret sk-live_42")
assert timeline.list_events("r1", after_seq=1) == []
assert timeline.list_events("r2")[0]["message"] == "secret [REDACTED]"

After these appends, run r1 has sequence 1 and run r2 has sequence 2. If the next r1 event arrives with an earlier timestamp, it still gets sequence 3. Listing r1 after cursor 1 returns that event; it doesn't reorder events by timestamp or renumber sequences per run.

The pattern is intentionally narrow. sk- alone and SK-live don't match; prefixsk-live! becomes prefix[REDACTED]!. This exercise doesn't recognize every possible credential format. Redact matched strings before storing them, and apply real retention and access policies separately.

Constraints

  • Keep state in memory.
  • Never expose events from other runs.
  • Run filtering is the storage contract here. A production API must also authorize the caller to read the requested run.

Editor