Signals: index the judge's query, six calls at once, one call per item on the server's key, tokens counted, a week's look-back an admin sets, edits that ask again only what was picked out (#274, #275, #276)
The judge's query read all of entries (605 MB, 566 ms) on every wake; an index on each feed's items by date, as the query asks, and the rechecks in a half of their own. Calls ran one at a time, about 150 ms each, so a new Signal's month of about 8,000 items took twenty minutes: six in flight now. On the server's key everyone's Signals on an item share one call. TypeSafe's token counts go to /metrics and each jev span. An item's text is cut at 1,000 characters instead of 2,000: on 55 real items of eight podcast feeds and six Signals, on the development key, 1,000 changed none of 330 verdicts (nor did the same request twice) and saved 12% of the input tokens, 1,266 to 1,112 a call; 500 changed one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -77,24 +77,33 @@ scan worker, so a slow TypeSafe never holds up a scan.
|
||||
`Db::unjudged` finds, newest first, up to 50 items that are:
|
||||
|
||||
- in a feed the Signal's owner subscribes to,
|
||||
- published (or, with no date, first seen) in the last 30 days (`SIGNAL_DAYS`),
|
||||
- not hidden from them by their block lists,
|
||||
- not yet in `signal_verdicts` for that Signal,
|
||||
- for someone with a key that TypeSafe has not refused since the daemon started.
|
||||
- for someone with a key that TypeSafe has not refused since the daemon started,
|
||||
- and either published (or, with no date, first seen) in the look-back window and not yet in
|
||||
`signal_verdicts` for that Signal, or picked out by it before it was edited (`recheck`), however
|
||||
old.
|
||||
|
||||
So a new Signal looks back a month, and after that sees each new item. A show subscribed to today
|
||||
has its back catalogue skipped, apart from its last month.
|
||||
The window is the admin's, Admin, Server, **Signals look back (days)** (`signal_days`, 7 by
|
||||
default, 1 to 365; #276): each item in it is a call, and a month of production's feeds was about
|
||||
8,000. So a new Signal looks back that far, and after that sees each new item. A show subscribed
|
||||
to today has its back catalogue skipped, apart from the window.
|
||||
|
||||
The recent half reads the index `entries_recent`, on each feed's items by date, the expression it
|
||||
is asked by; without it each wake read all of `entries`, 605 MB, 566 ms to find nothing (#274).
|
||||
|
||||
Rows for one item and one person are grouped, so an item is one call whatever the number of
|
||||
Signals. A full batch means there may be more, and the next pass starts at once. Otherwise the
|
||||
judge sleeps until woken or for 5 minutes.
|
||||
Signals. On the server's key, everyone's Signals on the same item go in one call too, its text
|
||||
sent once (#275). Six calls are in flight at once (`IN_FLIGHT`): one at a time, about 150 ms each,
|
||||
a month of items took twenty minutes. A full batch means there may be more, and the next pass
|
||||
starts at once. Otherwise the judge sleeps until woken or for 5 minutes.
|
||||
|
||||
### Every answer is kept
|
||||
|
||||
`signal_verdicts` records each answer, fitting or not. An item with no row has not been asked yet;
|
||||
an item with a row is never asked again. So the cost is one call per item per person, once.
|
||||
Changing a Signal's name, words or sentence deletes its verdicts, and everything in the window is
|
||||
asked again. The first start with sentences (#259) deleted every verdict, since they answered the
|
||||
Changing a Signal's name, words or sentence marks what it picked out to be asked again
|
||||
(`recheck`), and those stay in its list until answered; what it passed over stays passed over, and
|
||||
new items are asked the new question as they come (#276). The first start with sentences (#259) deleted every verdict, since they answered the
|
||||
old question.
|
||||
|
||||
## TypeSafe
|
||||
@@ -134,7 +143,9 @@ Sent with `Authorization: Bearer <the key>`, the server's or the person's, for a
|
||||
```
|
||||
|
||||
- `state` is text: the feed's title, the item's title, and its show notes with the HTML taken out,
|
||||
cut to 2,000 characters (`TEXT_CHARS`).
|
||||
cut to 1,000 characters (`TEXT_CHARS`). It was 2,000 until #275: on 55 real items and six
|
||||
Signals, 1,000 changed none of 330 verdicts and saved 12% of the input tokens (1,266 to 1,112 a
|
||||
call); 500 changed one. Most of the input is the questions themselves, not the item.
|
||||
- Each question is keyed `signal_<id>`, and its answer comes back under the same key.
|
||||
- `criteria` is an object saying what true and false mean. A sentence there is refused with a 422
|
||||
(#257).
|
||||
@@ -373,10 +384,10 @@ erDiagram
|
||||
- **Refused keys are remembered in memory**, so a restart tries each once again.
|
||||
- **Keywords changed while an item is being judged** can leave that one item's verdict from the old
|
||||
words.
|
||||
- **There is no meter** of how many calls a key has made. It is one call per item in the person's
|
||||
feeds in the window: a person with 1,500 feeds busy enough to publish 3,000 items a month spends
|
||||
about 3,000 calls the first month and then as many as come in.
|
||||
- **Only the last 30 days** are ever judged, by publish date.
|
||||
- **The meter is the server's**, `ipx_jev_tokens_total` and `ipx_jev_requests_total` on
|
||||
`/metrics`, and the Signals row of the dashboard: tokens as TypeSafe's answers count them. It is
|
||||
one call per item in the person's feeds as they come, and per item in the window for a new Signal.
|
||||
- **Only the window** is judged by publish date, apart from what an edit asks again.
|
||||
|
||||
## Testing
|
||||
|
||||
@@ -387,4 +398,6 @@ erDiagram
|
||||
- `npx playwright test -g Signal`: makes a Signal from the folder's +, and checks that the matching
|
||||
item shows and that reading it reads it in its feed and clears the badge. TypeSafe is stood in for
|
||||
by the fixture server's `/jev` (`IPX_TYPESAFE_URL`), which refuses the shape TypeSafe refuses, and
|
||||
`/signal.xml` is dated today, since only the last 30 days are judged.
|
||||
`/signal.xml` is dated today, since only the window is judged. They spend the TypeSafe key, so
|
||||
each runs only when the Signals code or the test has changed since it last passed (`signalsTest`;
|
||||
`IPX_SIGNALS_TESTS=1` runs them anyway).
|
||||
|
||||
Reference in New Issue
Block a user