Skip to content

Fixed ai - #94

Merged
slipmetal merged 13 commits into
devfrom
fixed-ai
Aug 9, 2026
Merged

Fixed ai#94
slipmetal merged 13 commits into
devfrom
fixed-ai

Conversation

@slipmetal

Copy link
Copy Markdown
Collaborator

No description provided.

Editors on Windows hosts were rewriting the whole tree to CRLF, which
turned 32 unrelated files into noise in every diff. Normalize on LF at
the git level and mirror it in the editor config.
Describe the trophy submission, avatar rotation and monthly survey flow,
the command reference, configuration, installation, project layout,
database schema and the Fly.io deployment pipeline.
A Python 3.12 container with a PostgreSQL service, so the bot can be run
against a local database without installing anything on the host.
get_chat_settings() asked for exactly one *Default* record, so the query
raised NoResultFound in every chat where no default avatar had been set.
The bot session used to be closed twice through asyncio.run() on an
already closed loop, and neither the scheduler nor the connection pool
was released at all. Close the session in a finally block, release both
resources from a dispatcher shutdown hook, and let Request own its
engine so it can be disposed and rebuilt.

Reconnection is now verified instead of assumed: check_db_connection()
re-runs the probe query after reconnecting and reports the outcome, and
the engine is created with pool_pre_ping so stale connections are
detected before a query uses them.
get_avatar() removed the record as part of reading it, so a failure in
set_chat_photo or send_photo — losing admin rights, for instance — threw
the trophy away without ever showing it. Return the record id instead and
delete it from change_avatar once the rotation has actually succeeded;
a failed rotation now simply retries on the next tick.

The result is returned as a QueuedAvatar named tuple: six positional
values, three of them strings in a row, were easy to unpack wrongly.
change_avatar() persisted the next date but never updated where_run, so
every rotation kept computing the interval from the same original date.
A malformed date or a non-numeric interval raised straight out of the
handler; both now answer with the expected format. /history no longer
falls back to the caller's username, which returned nothing for users
who have none — it looks the caller up by user id instead.
/set_date passes no interval and /set_delta passes no date, but the
missing half was only filled in when a job already existed. For a chat
that had no job yet — start() skips chats the bot was not a member of at
boot — /set_date reached IntervalTrigger with days=None and raised
TypeError. A partially filled where_run entry was just as fatal later,
since change_avatar adds delta to date unguarded.

Resolve both values against the stored state before branching, falling
back to now and to DEFAULT_DELTA, and always write the entry back whole.

This adds the first tests to the project, so it also brings the pytest
setup: the root conftest supplies the environment variables that
src.bot.settings reads at import time.
Also install the native libraries WeasyPrint and pdf2image need: the
lint step only parsed the sources, while the tests import them.
CI resolved pylint 3.3 from the compatible-release range while the dev
container ships 4.0.6, and the two disagree about R0917: 3.3 counts self
as a positional argument, 4.0 does not, so three signatures that pass
locally failed the lint step. Pin all three dev tools exactly.
The root carries an __init__.py, so pytest treats it as a package and
inserts its parent directory instead of the root itself. `import src`
therefore only resolved under `python -m pytest`, which injects the cwd
on its own; the bare `pytest` that CI runs failed to collect at all.
@slipmetal
slipmetal requested a review from NickLyrick August 9, 2026 13:23
aiogram 3.5 -> 3.30 brings two breaking changes that the code had to
follow: Bot() no longer takes parse_mode, so the default now goes through
DefaultBotProperties, and Telegram models are frozen, so the media
caption is set at construction instead of being assigned afterwards.

Also declare python-dateutil, which jobs.py imports directly and which
only arrived as a transitive dependency of pandas, and drop the typing
backport — it targets Python below 3.5 and has no business in a 3.12
image.
@slipmetal
slipmetal merged commit 8796b9e into dev Aug 9, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants