Skip to content

0002. The repetition engine reports events on the current span

Status: Accepted, 2026-08-23 (#175, closing #173); replaces the design of #124

Context

check_answer() and next_exercise() returned events that nothing but tracing used. The events themselves — an answer marked, a linked topic scheduled, nothing left to show — are worth seeing in traces. The constraint: wiederholen.school.tutoring deliberately has no infrastructure dependencies, so that Tutor can be tested without mocks.

The first design (#124) kept tutoring free of OpenTelemetry: check_answer() and next_exercise() returned their result together with a list of event dataclasses, and the bot turned each event into a span event at every call site (record_tutoring_events()). It turned out the bot was the only consumer of those lists, and it never looked at their content — for example, the "Study more" button depends only on next_exercise() returning None, not on the event's reason.

Decision

Tutor reports events by calling wiederholen.school.tutoring.events.emit() at the moment they happen. emit() adds a span event to trace.get_current_span(). check_answer() and next_exercise() return only their result. The events stay frozen dataclasses, declared next to the code that fires them, and are internal to tutoring.

tutoring now depends on opentelemetry-api, but not the SDK.

Alternatives considered

  • Return events to the caller (the #124 design). Keeps tutoring free of OpenTelemetry, but adds a second return value every caller has to unpack and forward, for a fact only tracing uses.
  • Inline span.add_event() calls with dict literals. Simpler, but scatters each event's shape across call sites; what an event contains is domain knowledge that belongs in one place.

Consequences

  • Tutor's methods have plain signatures again, and frontends need no tracing code for its events — the web app gets them for free.
  • The OpenTelemetry API is a no-op without a configured provider, so Tutor's tests needed no changes.
  • Testing an event means a recording provider and an in-memory exporter (the shared tracer/exporter fixtures) instead of asserting on a returned list.
  • tutoring's "no infrastructure" rule now has one documented exception: the OpenTelemetry API, never the SDK.