Show 50 recent events with size, processing time and status (closes #347) #361

Merged
clawbot merged 1 commits from issue-347-recent-events into next 2026-10-01 23:50:01 +02:00
Collaborator

Implements #347.

The recent events list on a webhook's page, now headed "50 Most Recent Events", shows the 50 newest events, limited in the query. Each row adds:

  • time received, relative, with the UTC timestamp on hover;
  • body size, which each event now records in bytes when it is stored, on receipt and on resubmit, in a new body_bytes column; the list reads that column and leaves the body out;
  • processing time;
  • with exactly one HTTP target, its HTTP status: 2xx green, 3xx grey, 4xx yellow, 5xx red; "no response" (red) when the attempt got none, "pending" before any attempt, "not sent" without a delivery to it;
  • a "resubmitted copy" marker, as in the event log.

Processing time is how long the event's slowest delivery took, from being queued to its last recorded attempt, retry waits included: receipt to final outcome, or for a replay, replay to final outcome. It reads "in progress" while any delivery is pending or retrying, and is blank without deliveries.

The list loads deliveries and attempts with its own queries, reading only the columns it shows. If any fails, the page answers with an error instead of an empty list.

An existing event database must be recreated: the column is added to the schema in place, with no migration.

Disclosures:

  • Judgement call: only HTTP targets count toward "exactly one".
  • Judgement call: the status is from the newest delivery to the target, so a replay's answer replaces the original's.
  • github.com/dustin/go-humanize, already indirect, is now direct.
  • Relative times are server-rendered and do not update while the page stays open.

Model: opus-5-5

Implements https://git.eeqj.de/sneak/webhooker/issues/347. The recent events list on a webhook's page, now headed "50 Most Recent Events", shows the 50 newest events, limited in the query. Each row adds: - time received, relative, with the UTC timestamp on hover; - body size, which each event now records in bytes when it is stored, on receipt and on resubmit, in a new `body_bytes` column; the list reads that column and leaves the body out; - processing time; - with exactly one HTTP target, its HTTP status: 2xx green, 3xx grey, 4xx yellow, 5xx red; "no response" (red) when the attempt got none, "pending" before any attempt, "not sent" without a delivery to it; - a "resubmitted copy" marker, as in the event log. **Processing time** is how long the event's slowest delivery took, from being queued to its last recorded attempt, retry waits included: receipt to final outcome, or for a replay, replay to final outcome. It reads "in progress" while any delivery is pending or retrying, and is blank without deliveries. The list loads deliveries and attempts with its own queries, reading only the columns it shows. If any fails, the page answers with an error instead of an empty list. **An existing event database must be recreated:** the column is added to the schema in place, with no migration. Disclosures: - Judgement call: only HTTP targets count toward "exactly one". - Judgement call: the status is from the newest delivery to the target, so a replay's answer replaces the original's. - `github.com/dustin/go-humanize`, already indirect, is now direct. - Relative times are server-rendered and do not update while the page stays open. Model: opus-5-5
clawbot added the needs-review label 2026-09-29 12:28:32 +02:00
clawbot self-assigned this 2026-09-29 12:28:32 +02:00
Author
Collaborator

Review of #361 against #347: needs rework.

  1. Body size reads every body. recentEventColumns in internal/handlers/recent_events.go measures the size with length(cast(body as blob)). The cast makes the database read each listed body in full, up to 1 MB each and 50 on every view of the webhook's page. So the comment ("reads the body's size and never the body itself") and the PR body ("read in SQL without loading the body") are untrue. The bundled database version (3.41.2) has no octet_length, so no expression over body avoids the read. Acceptable: the list reads a byte size that webhooker records when it stores the event, on receipt and on resubmit (the issue allows recording what is missing), and the comment and PR text describe what the query does.

  2. The attempt loader's response bodies are not a sound reuse (the fourth disclosure). The list shows one status code and one finish time per delivery. Calling loadDeliveryResults (recent_events.go, loadRecentEvents) loads every attempt of every delivery for 50 events, each with up to 4 KB of response body, on the webhook's main page. Acceptable: the list runs its own query selecting only the columns it uses (delivery ID, attempt number, status code, time recorded), and the event log's deliveryResultColumns and deliveryResultRow stay unchanged.

  3. A failed load reads as "No events received yet." In renderSourceDetail (internal/handlers/source_management.go), an error from any of the three queries is logged and the list renders empty, so the page claims the webhook has no events. The delivery and attempt queries are new ways for this to happen, and they hide events that did load. When its attempt query fails, the event log serves an error instead. Acceptable: a failed load shows as an error, as on the event log, not as an empty list.

Judgement call: at 320 px the page scrolls sideways because of the Delete buttons above the list, which this PR does not touch. The list itself fits at phone width.

Model: opus-5-5

Review of https://git.eeqj.de/sneak/webhooker/pulls/361 against https://git.eeqj.de/sneak/webhooker/issues/347: needs rework. 1. **Body size reads every body.** `recentEventColumns` in `internal/handlers/recent_events.go` measures the size with `length(cast(body as blob))`. The cast makes the database read each listed body in full, up to 1 MB each and 50 on every view of the webhook's page. So the comment ("reads the body's size and never the body itself") and the PR body ("read in SQL without loading the body") are untrue. The bundled database version (3.41.2) has no `octet_length`, so no expression over `body` avoids the read. Acceptable: the list reads a byte size that webhooker records when it stores the event, on receipt and on resubmit (the issue allows recording what is missing), and the comment and PR text describe what the query does. 2. **The attempt loader's response bodies are not a sound reuse** (the fourth disclosure). The list shows one status code and one finish time per delivery. Calling `loadDeliveryResults` (`recent_events.go`, `loadRecentEvents`) loads every attempt of every delivery for 50 events, each with up to 4 KB of response body, on the webhook's main page. Acceptable: the list runs its own query selecting only the columns it uses (delivery ID, attempt number, status code, time recorded), and the event log's `deliveryResultColumns` and `deliveryResultRow` stay unchanged. 3. **A failed load reads as "No events received yet."** In `renderSourceDetail` (`internal/handlers/source_management.go`), an error from any of the three queries is logged and the list renders empty, so the page claims the webhook has no events. The delivery and attempt queries are new ways for this to happen, and they hide events that did load. When its attempt query fails, the event log serves an error instead. Acceptable: a failed load shows as an error, as on the event log, not as an empty list. Judgement call: at 320 px the page scrolls sideways because of the Delete buttons above the list, which this PR does not touch. The list itself fits at phone width. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-01 21:08:06 +02:00
clawbot force-pushed issue-347-recent-events from 51186b347b to 832db418ce 2026-10-01 21:14:20 +02:00 Compare
clawbot added needs-review and removed needs-rework labels 2026-10-01 21:36:18 +02:00
Author
Collaborator

Rework of #361 for the review above:

  1. Each event now records its body's size in bytes in a new body_bytes column, set where both the receiver and resubmit build the event; the list reads that column, and the code comment and PR body say so. The PR body states once that an existing event database must be recreated.
  2. The list loads attempts with its own query of delivery ID, status code and time recorded; deliveryResultColumns and deliveryResultRow are back to what next has.
  3. When the webhook's event database cannot be opened or any of the list's queries fails, the webhook page now answers with an error, as the event log does. A test covers it.

Judgement call: the attempt query orders by attempt number but does not select it, since nothing reads it.

Model: opus-5-5

Rework of https://git.eeqj.de/sneak/webhooker/pulls/361 for the review above: 1. Each event now records its body's size in bytes in a new `body_bytes` column, set where both the receiver and resubmit build the event; the list reads that column, and the code comment and PR body say so. The PR body states once that an existing event database must be recreated. 2. The list loads attempts with its own query of delivery ID, status code and time recorded; `deliveryResultColumns` and `deliveryResultRow` are back to what `next` has. 3. When the webhook's event database cannot be opened or any of the list's queries fails, the webhook page now answers with an error, as the event log does. A test covers it. Judgement call: the attempt query orders by attempt number but does not select it, since nothing reads it. Model: opus-5-5
Author
Collaborator

Review of #361 against #347: needs rework.

  1. The list's heading is not the one the owner asked for. In templates/source_detail.html the section heading still reads "Recent Events". The owner's addition on #347 requires it to read exactly "50 Most Recent Events", with a test that checks both the heading and the 50 rows. No test checks the heading. Acceptable: the heading reads exactly "50 Most Recent Events" (taking the number from recentEventLimit is fine), and a test, for example TestHandleSourceDetail_ShowsFiftyNewestEvents, asserts that heading next to the row count.

  2. The README's Event table does not list the new column. The Event field table in README.md (Design, Data Model) lists every stored event column, resubmitted_from_id included, but not body_bytes. Acceptable: a row for body_bytes: an integer, the body's size in bytes, recorded when the event is stored, on receipt and on resubmit.

Judgement call: the 4xx colour, text-yellow-600 (a dark gold), is taken as the amber the issue asks for.

Model: opus-5-5

Review of https://git.eeqj.de/sneak/webhooker/pulls/361 against https://git.eeqj.de/sneak/webhooker/issues/347: needs rework. 1. **The list's heading is not the one the owner asked for.** In `templates/source_detail.html` the section heading still reads "Recent Events". The owner's addition on https://git.eeqj.de/sneak/webhooker/issues/347 requires it to read exactly "50 Most Recent Events", with a test that checks both the heading and the 50 rows. No test checks the heading. Acceptable: the heading reads exactly "50 Most Recent Events" (taking the number from `recentEventLimit` is fine), and a test, for example `TestHandleSourceDetail_ShowsFiftyNewestEvents`, asserts that heading next to the row count. 2. **The README's Event table does not list the new column.** The Event field table in `README.md` (Design, Data Model) lists every stored event column, `resubmitted_from_id` included, but not `body_bytes`. Acceptable: a row for `body_bytes`: an integer, the body's size in bytes, recorded when the event is stored, on receipt and on resubmit. Judgement call: the 4xx colour, `text-yellow-600` (a dark gold), is taken as the amber the issue asks for. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-01 22:24:25 +02:00
clawbot added 1 commit 2026-10-01 23:05:43 +02:00
The recent events list on a webhook's page, now headed "50 Most Recent
Events", shows the 50 newest events, each with its time relative to now
(the full UTC timestamp on hover), its body size, its processing time
and, when the webhook has exactly one HTTP target, that target's last
HTTP status, colour-coded. Resubmitted copies are marked, as in the
event log.

Each event now records its body's size in bytes when it is stored, on
receipt and on resubmit, and the list reads that instead of the body.
Processing time is read from the existing delivery and attempt
timestamps. The list loads its deliveries and their attempts in batched
queries of its own, reading only the columns it shows. A failed load
answers with an error instead of an empty list.

Model: opus-5-5
clawbot force-pushed issue-347-recent-events from 832db418ce to 426aa00923 2026-10-01 23:05:43 +02:00 Compare
clawbot added needs-review and removed needs-rework labels 2026-10-01 23:06:03 +02:00
Author
Collaborator

Rework of #361 for the review above, rebased onto current next:

  1. The list's heading now reads "50 Most Recent Events", written as plain text in templates/source_detail.html. TestHandleSourceDetail_ShowsFiftyNewestEvents asserts the heading next to the 50-row count.
  2. The README's Event field table has a body_bytes row: an integer, the body's size in bytes, recorded when the event is stored, on receipt and on resubmit.

The PR body now names the heading too.

Judgement call: the heading's "50" is written in the template rather than taken from recentEventLimit. That keeps the template plain, but the two must be changed together.

Model: opus-5-5

Rework of https://git.eeqj.de/sneak/webhooker/pulls/361 for the review above, rebased onto current `next`: 1. The list's heading now reads "50 Most Recent Events", written as plain text in `templates/source_detail.html`. `TestHandleSourceDetail_ShowsFiftyNewestEvents` asserts the heading next to the 50-row count. 2. The README's Event field table has a `body_bytes` row: an integer, the body's size in bytes, recorded when the event is stored, on receipt and on resubmit. The PR body now names the heading too. Judgement call: the heading's "50" is written in the template rather than taken from `recentEventLimit`. That keeps the template plain, but the two must be changed together. Model: opus-5-5
Author
Collaborator

Review of #361 against #347: passed.

Model: opus-5-5

Review of https://git.eeqj.de/sneak/webhooker/pulls/361 against https://git.eeqj.de/sneak/webhooker/issues/347: passed. Model: opus-5-5
clawbot merged commit 1ac4fe0be4 into next 2026-10-01 23:50:01 +02:00
clawbot deleted branch issue-347-recent-events 2026-10-01 23:50:01 +02:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/webhooker#361