2 Commits
Author SHA1 Message Date
cgalo5758 340f19e21c List same-instant feed events by kind, then the later-written row first
Events of the recent-activity feed that share one timestamp now list by
kind (grant, invoice, payment, tier change, as before) and, within a kind,
the one the console recorded later first. Invoice and payment events had no
Seq, so two of them at one instant fell through to their summary text and
organization id: "$100.00" listed above "$20.00" and Zeta above Alpha
whichever was recorded later. They now carry their own row's id, as grant
and tier events already did, and activityLess breaks the tie on it, so
every event has one place in the order. The comment on ActivityEvent.Seq
and on activityLess say so. The requirement "Invoice and payment events
are placed when they happened" now states the order of events that share
one timestamp, through the change same-instant-feed-order, archived in
this commit with the delta synced into the main spec.

How it was shown to change only that: TestRecentActivityTiesListTheLaterWrittenFirst
(invoices of two organizations, invoices of one organization, rows of one
kind in any input order) fails in all three subtests at the parent and
passes here. The feed's golden diff is exactly two pairs of rows swapped in
feed.json and in feed.html: Alpha's invoice above Zeta's, and "$20.00"
above "$100.00" for the invoices of one organization. Names and results of
internal/server are equal to the parent's (1473 at the parent, 1477 here:
the new test and its three subtests), 0 failures. Four breaks (the invoice
Seq, the payment Seq, the id direction, the kind direction) are each caught
by the new test or the feed's golden. The lint snapshot is unchanged
(0 added, 0 removed). Walkthroughs are equal at the parent and here (16
pass, 6 skip); screens at the parent and here differ from the baseline only
in the masked regions, so operator-overview is unchanged: the demo feed
holds no same-kind ties.

Unprobed: payments tied in the database. The database subtests tie
invoices only; ties of payments, and of three rows of one kind, are checked
without a database through the comparator, because the tie rests on the
payment row carrying its id, which the comparator check and the payment
break cover.
2026-10-10 20:42:09 -05:00
cgalo5758 2fd63eaca2 Characterize the recent-activity feed: its rows, its failed reads, its reads per event and the landing's paging
No production file changes. The feed's output is unchanged because nothing
the page runs was edited; the commit adds tests, one kit function and the
files the golden compares with.

TestRecentActivityGolden builds nine organizations on one World, for ten
cases (the floor, an upgrade and a revocation on a plan the type defaults
to; an upgrade by a subscription that then ends and resumes the grant; a
live extension; an extension of a grant on hold; a ladder of its own; a
reorder after the tier changes; the console's own removal of a tier, which
writes the only end row with no rank; invoices and payments around one
instant; two organizations with one invoice each at one instant). It
compares the events the feed lists for them, in order, as JSON, and the
activity panel's render of those events, with files under
testdata/operator_activity. Instants are named t01 and on, newest first,
because only their order is a fact. The files were read against the fixture
before they were committed. The feed's four existing readers now go through
wholeFeed.

TestRecentActivityReadFailures fails each of ten reads in turn (the four
sources, the product, the tiers, the organization, the person, a handler
without a database and a closed one) and pins the events the feed keeps and
the warning it writes. TestRecentActivityReadsPerEvent grows the feed by two
organizations on a scratch database and expects exactly the product,
ladder, organization and person reads of two more of each, and no change in
the four source reads or the raw ladder read. The landing page tests read
GET /operator on a scratch database: each source is cut at 100 rows (the
101st invoice is on no page and the pager counts the 101 events the feed
holds), and a feed of 30 events pages by act_page and act_per, with a page
past the end showing page 1 and an unknown size reading as 10.
dbtest.CountedAt is Counted over a given address.

Shown to change no output: 33 breaks of the feed's code, each applied on its
own, are all caught by the new tests; the tests of ./internal/server and
./internal/testkit/... pass three times in a row, each on a reset database,
with no test or subtest of the parent missing or changed in result and 19
added in ./internal/server (the golden, the failure table and its ten
subtests, the reads test, the cut test, the paging test and its four
subtests); the golden passes a second run without -update and leaves the
tree unchanged.

Unprobed, and why:
- Each source is read once per render: no one-line edit doubles a source
  read without also changing the rows.
- The order of two warnings when two sources fail: no subtest fails two
  reads.
- The When cells: the golden replaces them with tokens, and the test of
  billing events' times pins their text.
- The template's id fallback for an unnamed organization or actor: the
  overview render tests, which build their events by hand, pin it.
- An extension older than the transitions window shows as its grant row:
  pinning it needs about 100 later tier changes.
2026-10-09 21:23:00 -05:00