Show each webhook's activity in the webhook list (closes #394) #417

Merged
clawbot merged 1 commits from issue-394-list-activity into next 2026-10-02 13:57:43 +02:00
Collaborator

Each entry in the webhook list at /hooks now shows when the webhook's last event arrived, or "No events yet", how many of its deliveries failed in the last 24 hours, in red when that is not zero, and how many of its entrypoints and targets are inactive, as in "4 targets, 1 inactive".

The figures reuse the counts from #368: the last arrival comes from the event totals row, and the failures from the statistics pane's own query over the deliveries that finished in the last 24 hours. The event count now also comes from the totals row instead of counting every stored event, so it matches the pane's "within retention" figure.

Cost: for each webhook the list reads its entrypoints' and targets' active flags from the main database and, when the webhook has an event database, opens it once (the handle stays open afterwards) and runs two reads there. The page's work grows linearly with the number of webhooks and, for each, with the deliveries that finished in the last 24 hours; it no longer grows with the number of events stored.

A webhook whose event database cannot be read says so in its entry, and the rest of the list still shows.

  • Deviation: a failure reading entrypoints or targets from the main database now returns an error page; before, it was ignored and showed zero.
  • Judgement call: the inactive count is shown only when it is not zero.

Model: opus-5-5

Each entry in the webhook list at `/hooks` now shows when the webhook's last event arrived, or "No events yet", how many of its deliveries failed in the last 24 hours, in red when that is not zero, and how many of its entrypoints and targets are inactive, as in "4 targets, 1 inactive". The figures reuse the counts from https://git.eeqj.de/sneak/webhooker/issues/368: the last arrival comes from the event totals row, and the failures from the statistics pane's own query over the deliveries that finished in the last 24 hours. The event count now also comes from the totals row instead of counting every stored event, so it matches the pane's "within retention" figure. Cost: for each webhook the list reads its entrypoints' and targets' active flags from the main database and, when the webhook has an event database, opens it once (the handle stays open afterwards) and runs two reads there. The page's work grows linearly with the number of webhooks and, for each, with the deliveries that finished in the last 24 hours; it no longer grows with the number of events stored. A webhook whose event database cannot be read says so in its entry, and the rest of the list still shows. - Deviation: a failure reading entrypoints or targets from the main database now returns an error page; before, it was ignored and showed zero. - Judgement call: the inactive count is shown only when it is not zero. Model: opus-5-5
clawbot self-assigned this 2026-10-02 07:11:21 +02:00
clawbot added the needs-review label 2026-10-02 07:11:24 +02:00
Author
Collaborator

Review of #417 against #394: needs rework.

  1. templates/sources_list.html line 36: the event count is now the within-retention figure from the EventTotals row (the README paragraph this PR adds says so), but the entry still reads only "12 events". The webhook page's statistics pane shows events both lifetime and within retention, so the list does not say which of the two its figure is. Acceptable: the label names it, for example "12 events within retention", and the test assertions follow.

  2. internal/handlers/source_list_test.go: no test has events removed by retention, so the new source of the event count is untested where it matters. A list that showed lifetime events instead of events within retention would pass every test. Acceptable: a test in which retention has removed some of a webhook's events, asserting that the list shows only the events still stored.

  3. internal/handlers/source_list_test.go line 196: the webhook with no events is made without an event database, a state the app never produces (creating a webhook creates its event database, internal/handlers/source_management.go line 422). The path a real new webhook takes, an event database whose totals are all zero, is untested for the list. Acceptable: the no-events case uses a webhook with its event database, as the app creates it, and asserts "0 events", "No events yet", "0 failed deliveries in the last 24 hours" and no highlight. The existing case without a database can stay.

Judgement call: the disclosed deviation, an error page when entrypoints or targets cannot be read from the main database, is accepted; it matches how the list already handles a failure to read the webhooks themselves.

Model: opus-5-5

Review of https://git.eeqj.de/sneak/webhooker/pulls/417 against https://git.eeqj.de/sneak/webhooker/issues/394: needs rework. 1. `templates/sources_list.html` line 36: the event count is now the within-retention figure from the `EventTotals` row (the README paragraph this PR adds says so), but the entry still reads only "12 events". The webhook page's statistics pane shows events both lifetime and within retention, so the list does not say which of the two its figure is. Acceptable: the label names it, for example "12 events within retention", and the test assertions follow. 2. `internal/handlers/source_list_test.go`: no test has events removed by retention, so the new source of the event count is untested where it matters. A list that showed lifetime events instead of events within retention would pass every test. Acceptable: a test in which retention has removed some of a webhook's events, asserting that the list shows only the events still stored. 3. `internal/handlers/source_list_test.go` line 196: the webhook with no events is made without an event database, a state the app never produces (creating a webhook creates its event database, `internal/handlers/source_management.go` line 422). The path a real new webhook takes, an event database whose totals are all zero, is untested for the list. Acceptable: the no-events case uses a webhook with its event database, as the app creates it, and asserts "0 events", "No events yet", "0 failed deliveries in the last 24 hours" and no highlight. The existing case without a database can stay. Judgement call: the disclosed deviation, an error page when entrypoints or targets cannot be read from the main database, is accepted; it matches how the list already handles a failure to read the webhooks themselves. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-02 07:40:56 +02:00
clawbot force-pushed issue-394-list-activity from 1692453bbd to b93ecf4cb1 2026-10-02 08:06:53 +02:00 Compare
clawbot added needs-review and removed needs-rework labels 2026-10-02 08:07:01 +02:00
Author
Collaborator

Rework of #417, rebased onto next:

  1. Each entry's event count now reads "N events within retention", and the test assertions use that wording.
  2. New test: a webhook with 14 days of retention receives three events, one is aged past retention and the real retention reaper removes it. The list then shows "2 events within retention", matching the two events still stored.
  3. The activity test adds a webhook whose event database is created the way creating a webhook creates it, and checks "0 events within retention", "No events yet", "0 failed deliveries in the last 24 hours" and no red highlight. The case without an event database stays.

Model: opus-5-5

Rework of https://git.eeqj.de/sneak/webhooker/pulls/417, rebased onto `next`: 1. Each entry's event count now reads "N events within retention", and the test assertions use that wording. 2. New test: a webhook with 14 days of retention receives three events, one is aged past retention and the real retention reaper removes it. The list then shows "2 events within retention", matching the two events still stored. 3. The activity test adds a webhook whose event database is created the way creating a webhook creates it, and checks "0 events within retention", "No events yet", "0 failed deliveries in the last 24 hours" and no red highlight. The case without an event database stays. Model: opus-5-5
Author
Collaborator

Review of #417 against #394, rebased onto the current next: needs rework. The three earlier findings are fixed.

  1. internal/handlers/source_management.go, HandleSourceList: when buildWebhookListItems fails, the handler logs and answers with http.Error, a bare plain-text 500. On the current next, #382 makes every 500 on an admin page the error page in the normal layout, and the webhook read just above this line in the same handler already goes through h.serverError. Merged as it is, this brings a bare-text 500 back to /hooks. Acceptable: rebase onto next and answer this failure with h.serverError, the same way as the webhook read above it.

  2. internal/handlers/source_list_test.go, TestSourceList_CountsOnlyEventsWithinRetention: after retention runs, the test checks only the event count. Two wrong versions of the list would pass every test: one that takes the last event from the newest stored event, and one that says "No events yet" whenever no events are stored. Once retention has removed all of a webhook's events, both would show the wrong last event. The statistics pane keeps the last event through retention, and so does this list today. Acceptable: a case where retention removes every event of a webhook, asserting "0 events within retention" and "Last event" with the newest event's arrival time in UTC, not "No events yet".

Judgement call: the tests check the UTC conversion only on a host whose time zone is UTC, as for the statistics pane; not raised.

Model: opus-5-5

Review of https://git.eeqj.de/sneak/webhooker/pulls/417 against https://git.eeqj.de/sneak/webhooker/issues/394, rebased onto the current `next`: needs rework. The three earlier findings are fixed. 1. `internal/handlers/source_management.go`, `HandleSourceList`: when `buildWebhookListItems` fails, the handler logs and answers with `http.Error`, a bare plain-text 500. On the current `next`, https://git.eeqj.de/sneak/webhooker/issues/382 makes every 500 on an admin page the error page in the normal layout, and the webhook read just above this line in the same handler already goes through `h.serverError`. Merged as it is, this brings a bare-text 500 back to `/hooks`. Acceptable: rebase onto `next` and answer this failure with `h.serverError`, the same way as the webhook read above it. 2. `internal/handlers/source_list_test.go`, `TestSourceList_CountsOnlyEventsWithinRetention`: after retention runs, the test checks only the event count. Two wrong versions of the list would pass every test: one that takes the last event from the newest stored event, and one that says "No events yet" whenever no events are stored. Once retention has removed all of a webhook's events, both would show the wrong last event. The statistics pane keeps the last event through retention, and so does this list today. Acceptable: a case where retention removes every event of a webhook, asserting "0 events within retention" and "Last event" with the newest event's arrival time in UTC, not "No events yet". Judgement call: the tests check the UTC conversion only on a host whose time zone is UTC, as for the statistics pane; not raised. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-02 09:17:26 +02:00
clawbot force-pushed issue-394-list-activity from b93ecf4cb1 to a4337e949b 2026-10-02 09:34:44 +02:00 Compare
Author
Collaborator

Rework of #417, rebased onto next:

  1. When the list's entries cannot be built, HandleSourceList now answers with h.serverError, like the webhook read above it, so /hooks shows the error page from #382.
  2. New test: a webhook's only event is aged past its retention and the real retention reaper removes it. The list then shows "0 events within retention" and "Last event" with that event's arrival time in UTC, not "No events yet".

No other error path this PR adds returns a bare 500. A webhook whose event database cannot be read is still reported in its own entry, as the issue plan says, and the rest of the list is shown.

Model: opus-5-5

Rework of https://git.eeqj.de/sneak/webhooker/pulls/417, rebased onto `next`: 1. When the list's entries cannot be built, `HandleSourceList` now answers with `h.serverError`, like the webhook read above it, so `/hooks` shows the error page from https://git.eeqj.de/sneak/webhooker/issues/382. 2. New test: a webhook's only event is aged past its retention and the real retention reaper removes it. The list then shows "0 events within retention" and "Last event" with that event's arrival time in UTC, not "No events yet". No other error path this PR adds returns a bare 500. A webhook whose event database cannot be read is still reported in its own entry, as the issue plan says, and the rest of the list is shown. Model: opus-5-5
clawbot added needs-review and removed needs-rework labels 2026-10-02 09:34:54 +02:00
Author
Collaborator

Review of #417 against #394, rebased onto the current next: needs rework.

  1. internal/handlers/source_list_test.go, seedFailingWebhook (line 105) and the first assertion in TestSourceList_ShowsActivityOfEachWebhook: the failing webhook has one inactive entrypoint and one inactive target. A list that put the inactive-entrypoint count on the targets and the inactive-target count on the entrypoints would pass every test. Acceptable: give the failing webhook a different number of inactive entrypoints and inactive targets, for example one inactive entrypoint and two inactive targets, and assert each count on its own line ("2 entrypoints, 1 inactive", "4 targets, 2 inactive").

  2. internal/handlers/source_list_test.go, seedFailingWebhook (lines 130 to 138): every failure in the last 24 hours is on the same target, first. A list that showed one target's failures, instead of the total over all of the webhook's targets, would pass every test. Acceptable: put the failures from the last 24 hours on at least two targets, and assert that the list shows their total.

  • Judgement call: the conversion to UTC is still checked only on a host whose time zone is UTC, the same as for the statistics pane. Not raised, following the previous review's ruling.
  • Unverified item: I checked by reading the code, not on a running server, that a failure reading the main database on /hooks shows the error page from #382.

Model: opus-5-5

Review of https://git.eeqj.de/sneak/webhooker/pulls/417 against https://git.eeqj.de/sneak/webhooker/issues/394, rebased onto the current `next`: needs rework. 1. `internal/handlers/source_list_test.go`, `seedFailingWebhook` (line 105) and the first assertion in `TestSourceList_ShowsActivityOfEachWebhook`: the failing webhook has one inactive entrypoint and one inactive target. A list that put the inactive-entrypoint count on the targets and the inactive-target count on the entrypoints would pass every test. Acceptable: give the failing webhook a different number of inactive entrypoints and inactive targets, for example one inactive entrypoint and two inactive targets, and assert each count on its own line ("2 entrypoints, 1 inactive", "4 targets, 2 inactive"). 2. `internal/handlers/source_list_test.go`, `seedFailingWebhook` (lines 130 to 138): every failure in the last 24 hours is on the same target, `first`. A list that showed one target's failures, instead of the total over all of the webhook's targets, would pass every test. Acceptable: put the failures from the last 24 hours on at least two targets, and assert that the list shows their total. - Judgement call: the conversion to UTC is still checked only on a host whose time zone is UTC, the same as for the statistics pane. Not raised, following the previous review's ruling. - Unverified item: I checked by reading the code, not on a running server, that a failure reading the main database on `/hooks` shows the error page from https://git.eeqj.de/sneak/webhooker/issues/382. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-02 10:41:43 +02:00
clawbot force-pushed issue-394-list-activity from a4337e949b to 27ce0054e6 2026-10-02 11:29:38 +02:00 Compare
clawbot added needs-review and removed needs-rework labels 2026-10-02 11:29:45 +02:00
Author
Collaborator

Rework of #417, rebased onto next:

  1. The failing webhook now has six entrypoints, two of them inactive, and seven targets, five of them inactive, and each line has its own assertion.
  2. Its three failed deliveries in the last 24 hours are on two targets, two on one and one on the other, and the test checks the list's total.

Throughout the list tests, every figure on an entry now differs from every other figure on that entry, and each figure a test checks has its own assertion. Every webhook has at least two entrypoints and two targets, in different numbers, and each count that adds up entrypoints, targets, events or failed deliveries comes from more than one of them. The failing webhook's events arrive at different times, so only the newest one matches its last event.

  • Judgement call: an entry with no events necessarily shows zero events and zero failed deliveries, so those two figures cannot differ there; the failing webhook's entry tells them apart.
  • Judgement call: no entry has a count of one any more, so the singular wording ("1 entrypoint", "1 target") is no longer checked.

Model: opus-5-5

Rework of https://git.eeqj.de/sneak/webhooker/pulls/417, rebased onto `next`: 1. The failing webhook now has six entrypoints, two of them inactive, and seven targets, five of them inactive, and each line has its own assertion. 2. Its three failed deliveries in the last 24 hours are on two targets, two on one and one on the other, and the test checks the list's total. Throughout the list tests, every figure on an entry now differs from every other figure on that entry, and each figure a test checks has its own assertion. Every webhook has at least two entrypoints and two targets, in different numbers, and each count that adds up entrypoints, targets, events or failed deliveries comes from more than one of them. The failing webhook's events arrive at different times, so only the newest one matches its last event. - Judgement call: an entry with no events necessarily shows zero events and zero failed deliveries, so those two figures cannot differ there; the failing webhook's entry tells them apart. - Judgement call: no entry has a count of one any more, so the singular wording ("1 entrypoint", "1 target") is no longer checked. Model: opus-5-5
Author
Collaborator

Review of #417 against #394, rebased onto the current next: needs rework. The findings of the three earlier reviews are fixed.

  1. templates/sources_list.html lines 31, 32, 36 and 38 write the singular when a count is one ("1 entrypoint", "1 target", "1 event within retention", "1 failed delivery in the last 24 hours"), but since the last rework no test has a count of one, so a list that got any of these wrong would pass every test. Every webhook the app creates starts with one entrypoint, so "1 entrypoint" is the most common entry in the list. The rework's judgement call to leave the singular wording unchecked is not accepted. Acceptable: a test in internal/handlers/source_list_test.go with a webhook that has one entrypoint, one target, one event within retention and one failed delivery in the last 24 hours, asserting each of those four phrases.

  2. internal/handlers/source_list_test.go, seedFailingWebhook: three of the failing webhook's deliveries are left pending, the same number as its deliveries that failed in the last 24 hours, and the other webhooks have none of either. A list that showed the statistics pane's "Deliveries in progress" in place of the failed deliveries in the last 24 hours would pass every test. Acceptable: the failing webhook has a number of deliveries still pending or retrying that differs from its failed deliveries in the last 24 hours, so the existing assertion tells the two apart.

  3. internal/handlers/source_list_test.go: every last event the tests check is set by receiving an event while the test runs, so it falls in the same second as the webhook's creation and as the other webhooks' last events, and the list shows it to the second. A list that showed one webhook's last event on every entry, or each webhook's creation time in place of its last event, passes whenever the test's setup stays within one clock second. In TestSourceList_LastEventSurvivesPruningEveryEvent the event is aged 50 hours but the last-event time in the event totals row is not, so the time asserted is again the time of the run. Acceptable: each webhook's last event at a fixed time hours before the run and different for each webhook (for example set in its event totals row, along with any aged events), and each entry asserting its own.

  • Judgement call: the rework's other disclosure, that an entry with no events cannot tell zero events from zero failed deliveries, is accepted; the failing webhook's entry tells them apart.

Model: opus-5-5

Review of https://git.eeqj.de/sneak/webhooker/pulls/417 against https://git.eeqj.de/sneak/webhooker/issues/394, rebased onto the current `next`: needs rework. The findings of the three earlier reviews are fixed. 1. `templates/sources_list.html` lines 31, 32, 36 and 38 write the singular when a count is one ("1 entrypoint", "1 target", "1 event within retention", "1 failed delivery in the last 24 hours"), but since the last rework no test has a count of one, so a list that got any of these wrong would pass every test. Every webhook the app creates starts with one entrypoint, so "1 entrypoint" is the most common entry in the list. The rework's judgement call to leave the singular wording unchecked is not accepted. Acceptable: a test in `internal/handlers/source_list_test.go` with a webhook that has one entrypoint, one target, one event within retention and one failed delivery in the last 24 hours, asserting each of those four phrases. 2. `internal/handlers/source_list_test.go`, `seedFailingWebhook`: three of the failing webhook's deliveries are left pending, the same number as its deliveries that failed in the last 24 hours, and the other webhooks have none of either. A list that showed the statistics pane's "Deliveries in progress" in place of the failed deliveries in the last 24 hours would pass every test. Acceptable: the failing webhook has a number of deliveries still pending or retrying that differs from its failed deliveries in the last 24 hours, so the existing assertion tells the two apart. 3. `internal/handlers/source_list_test.go`: every last event the tests check is set by receiving an event while the test runs, so it falls in the same second as the webhook's creation and as the other webhooks' last events, and the list shows it to the second. A list that showed one webhook's last event on every entry, or each webhook's creation time in place of its last event, passes whenever the test's setup stays within one clock second. In `TestSourceList_LastEventSurvivesPruningEveryEvent` the event is aged 50 hours but the last-event time in the event totals row is not, so the time asserted is again the time of the run. Acceptable: each webhook's last event at a fixed time hours before the run and different for each webhook (for example set in its event totals row, along with any aged events), and each entry asserting its own. - Judgement call: the rework's other disclosure, that an entry with no events cannot tell zero events from zero failed deliveries, is accepted; the failing webhook's entry tells them apart. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-02 13:05:45 +02:00
clawbot added 1 commit 2026-10-02 13:42:04 +02:00
Each entry in the webhook list now shows when the webhook's last event
arrived, or "No events yet", and how many of its deliveries failed in
the last 24 hours, in red when that is not zero. The entrypoint and
target counts say how many are inactive.

The figures come from the statistics pane's own reads: the event totals
row, which now also gives the event count, shown as events within
retention, instead of counting every stored event, and the pane's query
over the deliveries finished in the last 24 hours. A webhook whose event
database cannot be read says so in its entry rather than showing zeros.

Model: opus-5-5
clawbot force-pushed issue-394-list-activity from 27ce0054e6 to d085c278e2 2026-10-02 13:42:04 +02:00 Compare
clawbot added needs-review and removed needs-rework labels 2026-10-02 13:42:14 +02:00
Author
Collaborator

Rework of #417, rebased onto next:

  1. New test TestSourceList_CountsOfOneInSingular: a webhook with one entrypoint, one target and one event, whose delivery failed an hour ago. It checks "1 entrypoint", "1 target", "1 event within retention" and "1 failed delivery in the last 24 hours" against the entry's markup, so a plural form cannot match.
  2. One more of the failing webhook's deliveries is now delivered, which leaves two pending against its three failed deliveries in the last 24 hours.
  3. Each webhook's newest event is moved back to a fixed time, and that time is recorded as its last event in its event totals row: 3 hours ago for the failing webhook, 6 for the healthy one, 9 for the webhook in the new test, and 50 in TestSourceList_LastEventSurvivesPruningEveryEvent. Older events arrive before it, and each entry checks its own last event.
  • Partially verified: the final rebase onto next brought in only code comments and a new routing test, with no conflict, and was pushed without running the checks again.

Model: opus-5-5

Rework of https://git.eeqj.de/sneak/webhooker/pulls/417, rebased onto `next`: 1. New test `TestSourceList_CountsOfOneInSingular`: a webhook with one entrypoint, one target and one event, whose delivery failed an hour ago. It checks "1 entrypoint", "1 target", "1 event within retention" and "1 failed delivery in the last 24 hours" against the entry's markup, so a plural form cannot match. 2. One more of the failing webhook's deliveries is now delivered, which leaves two pending against its three failed deliveries in the last 24 hours. 3. Each webhook's newest event is moved back to a fixed time, and that time is recorded as its last event in its event totals row: 3 hours ago for the failing webhook, 6 for the healthy one, 9 for the webhook in the new test, and 50 in `TestSourceList_LastEventSurvivesPruningEveryEvent`. Older events arrive before it, and each entry checks its own last event. - Partially verified: the final rebase onto `next` brought in only code comments and a new routing test, with no conflict, and was pushed without running the checks again. Model: opus-5-5
Author
Collaborator

Review of #417 against #394 passed.

Model: opus-5-5

Review of https://git.eeqj.de/sneak/webhooker/pulls/417 against https://git.eeqj.de/sneak/webhooker/issues/394 passed. Model: opus-5-5
clawbot merged commit 9ade217222 into next 2026-10-02 13:57:43 +02:00
clawbot deleted branch issue-394-list-activity 2026-10-02 13:57:43 +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#417