constants.py subclassed opentelemetry.semconv.trace.SpanAttributes, which
is deprecated since semconv 1.25.0 (emits a DeprecationWarning; the pinned
0.63b1 has it live). Source the legacy span-attribute keys from the
non-deprecated _incubating attribute modules instead:
http.url / http.method / http.status_code <- _incubating http_attributes
db.name / db.statement / db.operation <- _incubating db_attributes
The stable http module renamed these (http.request.method, ...), so only
the incubating module preserves the original values. Custom keys
(db.instance/type/ip/port, error.*, result.*) stay literals.
Verified: emitted attribute keys are byte-identical before/after for every
key instrumentors.py reads, and importing constants no longer emits a
DeprecationWarning.
Replace per-message database queries with batch IN-clause queries in
channel message handlers. This eliminates the N+1 query pattern that
caused ~102 queries per channel page load (50 messages × 2 queries each).
Changes:
- Add get_reactions_by_message_ids() to MessageTable: single query
fetches all reactions for multiple messages using IN clause with
User JOIN, returns dict[message_id, list[Reactions]]
- Add get_thread_reply_counts_by_message_ids() to MessageTable: single
GROUP BY aggregate query returns (count, max_created_at) per parent,
replacing full object loads just to call len()
- Refactor get_channel_messages(): 102 → 4 queries per page
- Refactor get_pinned_channel_messages(): 22 → 3 queries per page
- Refactor get_channel_thread_messages(): 53 → 4 queries per page
- Refactor send_notification(): N+1 membership check → batch set lookup
pydub imports the stdlib `audioop`, removed in Python 3.13, so audio
preprocessing would break there. requires-python is already capped at
< 3.13; this one-line pointer flags what to handle (audioop-lts, or drop
pydub) before raising that cap.