Forum teuk.org

๐Ÿ“šโšก Mediabot v3 โ€” The Grimoire Finally Reads Every Page

in Mediabot ยท started by TeuK ยท 2w ago

TeuK ยท 2w ago

Development chronicle โ€” mb626 to mb628 ยท Full-period AI summaries, index-friendly date queries and a final runtime truth check

This round looks small from the command line, but it fixes something fundamental: when Mediabot says it summarized a period, it must have genuinely covered that period.

The work started with ai summary today, moved into MariaDB query efficiency, and ended with a final audit that forced the tests and runtime to tell exactly the same story.

No database schema change was required.


๐Ÿ“– mb626 โ€” A whole period means the whole period

Earlier work had already improved ai summary by raising the fetch ceiling and spreading the prompt sample across the messages that had been loaded.

That was better, but it still hid a structural limitation.

The database read itself remained equivalent to:

ORDER BY id_channel_log DESC
LIMIT 1500

On a channel with 4,000 messages in one day, ai summary today therefore read only the latest 1,500.

The sampler could distribute its 400 prompt messages beautifully โ€” but only inside that final slice of the day.

The grimoire claimed to have read the chapter while holding only its last pages.


โณ The period is now divided in time

When a requested period contains more messages than the direct-fetch ceiling, Mediabot now divides the actual time window into eight equal slices.

Conceptually:

00:00                                                    23:59
  |--------|--------|--------|--------|--------|--------|--------|--------|
      1        2        3        4        5        6        7        8

Each slice contributes its own share of messages.

This makes the fetched material representative of the entire period rather than only its busiest or most recent end.

The boundaries are calculated by MariaDB, and every slice remains a range on:

(id_channel, ts)

rather than applying a function to the timestamp column.


๐Ÿ”ข The total is now real

Before mb626, a capped read could only announce something approximate:

1500+ messages in the period

The command now performs an indexed COUNT(*) over the same requested period and the same optional nickname filter.

That matters.

A summary of one user must not announce the total traffic of the whole channel.

The result can now say:

4213 messages in the period - summarising a distributed sample of 400.

instead of exposing only the size of the internal fetch ceiling.


๐Ÿง  Small periods stay cheap

The new machinery does not punish ordinary requests.

If the requested period contains fewer messages than the ceiling, Mediabot keeps the simple path:

COUNT
  |
  +-- below ceiling --> one normal indexed read
  |
  +-- above ceiling --> eight bounded reads

So the more expensive sliced strategy is reserved for periods that actually require it.


โšก mb627 โ€” Stop asking MariaDB to scan the library

While reviewing the period code, another old class of query problems was worth finishing.

The database already has the useful composite index:

(id_channel, ts)

But an index cannot help much when SQL wraps the indexed timestamp column inside functions such as:

DATE(ts)
YEAR(ts)
MONTH(ts)
DAY(ts)

For a large CHANNEL_LOG, that difference matters.

Instead of:

DATE(ts) >= some_date

the query should preferably look like:

ts >= some_date

or a bounded interval:

ts >= start
AND ts < end

๐Ÿ—„๏ธ The three remaining date paths were converted

mb627 finishes three remaining opportunities.

365-day window

Before:

DATE(ts) >= CURDATE() - INTERVAL 365 DAY

After:

ts >= CURDATE() - INTERVAL 365 DAY

Current month

Before:

YEAR(ts) = ...
AND MONTH(ts) = ...

After:

[first day of current month,
 first day of next month)

onthisday for a known year

Before:

YEAR(ts) = ?
AND MONTH(ts) = ?
AND DAY(ts) = ?

After:

[start of requested day,
 start of following day)

These ranges express the same date selection while giving MariaDB a much better chance to use the timestamp portion of the index.


๐Ÿงญ One onthisday query deliberately stays different

Not every use of MONTH(ts) and DAY(ts) is automatically wrong.

The historical onthisday query that searches the same month and day across every year cannot be represented as one continuous timestamp interval.

Its purpose is inherently cross-year, and its grouping by year reflects that.

That query therefore remains in its functional form, with an explanation in the source so a future cleanup does not โ€œoptimizeโ€ it into incorrect behaviour.


๐Ÿชค Parameter counts are part of correctness

Turning one equality expression into a bounded range often repeats the same date expression twice:

ts >= X
AND
ts < X + 1 day

With placeholders, this also means supplying the corresponding values twice.

That is easy to get wrong while still producing syntactically valid SQL.

The regression test therefore checks not only the query shape but also:

  • number of placeholders;
  • number of bound values;
  • exact bind order.

Performance work is useless if the optimized query returns the wrong records.


๐Ÿ”’ mb628 โ€” The tests and runtime must agree

The final pre-commit audit found an important contradiction.

mb627 had correctly converted the onthisday top-talker query to an index-friendly day range.

But an older regression test still expected the previous form:

MONTH(ts) = ?
AND DAY(ts) = ?

Both statements could not simultaneously describe the current code.

The historical test was therefore updated to verify the new runtime contract, including the range and its bind arity.

This is precisely why old regression tests should survive long enough to challenge new optimizations โ€” and why they must be updated when the intended contract genuinely changes.


โฎ๏ธ ai summary last keeps its strict boundary

The period-slicing refactor introduced another tiny semantic drift.

Historically:

last

meant messages strictly after the timestamp recorded for the previous summary:

ts > previous_summary_timestamp

The generic range machinery had turned that lower boundary into:

ts >= previous_summary_timestamp

That could replay a message whose timestamp landed exactly on the saved second.

mb628 restores the strict > boundary for the first slice of last, while normal calendar periods continue using inclusive starts.


๐Ÿšซ Exact coverage now fails closed

mb626 introduced a truthful exact count before reading a large period.

That count is not merely cosmetic โ€” it determines whether Mediabot should use one read or the eight-slice strategy.

The final audit therefore tightened the failure mode.

If the exact period COUNT(*) cannot be obtained, Mediabot now returns:

DB error.

and stops.

It does not silently fall back to the old capped recent-message read.

Otherwise the original bug could reappear exactly when the mechanism designed to prevent it was unavailable.


๐Ÿงช Regression map

This commit is protected by the following focused tests:

709  historical onthisday date contract, now aligned with mb627
809  complete-period slicing and exact-count runtime behaviour
810  remaining sargable CHANNEL_LOG date predicates
811  final runtime/test coherence and recent test-number uniqueness

The final guard also verifies that recently added test numbers remain unique.

That small check matters after several development rounds where features and tests were renumbered before publication.


๐Ÿ“ˆ Why this matters on a real Mediabot database

These changes are not micro-optimizations for an empty development table.

CHANNEL_LOG is exactly the kind of table that grows continuously and makes innocent-looking date expressions expensive over time.

This round therefore improves two kinds of truth at once:

Application truth
    "today" really covers today

Database truth
    the query shape lets the index do its job

Regression truth
    tests describe the runtime that is actually committed

Those three need to stay aligned.


๐Ÿฐ Final parchment

The grimoire used to open the last pages of a long chapter, spread them neatly across the desk, and claim it had read the whole story.

Now it walks the shelves from beginning to end.

The librarian has also stopped inspecting every book just to find one date; the catalogue is finally being used where it can help.

And before the castle records the work in ink, the final proofreader checks one last thing:

the spell, the test and the story must all say the same thing.

You must be logged in to reply.