Compare commits
2
Commits
81901a862e
...
e79d54ba34
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e79d54ba34 | ||
|
|
1eade490c8 |
+16
-28
@@ -55,19 +55,6 @@ export interface BuildReview {
|
||||
* characters or matching a common test string do not qualify. They still appear in
|
||||
* full on the mint page, nothing is hidden, this strip is just a shop window.
|
||||
*/
|
||||
/** How many candidates to gather per card shown, so the ordering has a real choice. */
|
||||
const POOL_FACTOR = 12;
|
||||
|
||||
/**
|
||||
* How recent a review must still be to be promoted for having a named author.
|
||||
*
|
||||
* The ordering below prefers reviews whose author has a kind 0, and this is the leash
|
||||
* on that preference. Without it the strip would headline a named review from two
|
||||
* years ago under a heading that says "Latest reviews"; with it, a named review from
|
||||
* within the season can lead and anything older cannot.
|
||||
*/
|
||||
const PROMOTE_MAX_AGE_S = 90 * 24 * 60 * 60;
|
||||
|
||||
const TEST_STRINGS = new Set([
|
||||
'test', 'testing', 'test test', 'hello', 'hi', 'ok', 'okay', 'good', 'nice',
|
||||
'great', 'cool', 'gm', 'a', '.', '..', '...', 'asdf', 'qwerty', '123',
|
||||
@@ -227,29 +214,30 @@ export async function fetchLatestReviews(
|
||||
profile: null,
|
||||
});
|
||||
|
||||
if (candidates.length >= limit * POOL_FACTOR) break;
|
||||
// The scan runs newest first, so the first `limit` survivors are the latest
|
||||
// `limit` reviews. Nothing further down the list can outrank them.
|
||||
if (candidates.length >= limit) break;
|
||||
}
|
||||
|
||||
const profiles = await fetchProfiles(candidates.map((c) => c.pubkey));
|
||||
for (const review of candidates) review.profile = profiles.get(review.pubkey) ?? null;
|
||||
|
||||
/*
|
||||
* Recent reviews with a named author come first; everything else stays newest
|
||||
* first behind them.
|
||||
* Strict recency, newest first, as the last thing that happens to this list.
|
||||
*
|
||||
* Most review keys have published exactly one event in their life: the review
|
||||
* itself. Nothing can be fetched for them, so a strict recency order fills this
|
||||
* strip with anonymous npubs while a named review sits a few rows below the
|
||||
* cut. This is the home page shop window, which already drops junk bodies, so
|
||||
* it prefers a review a reader can attach a person to. Nothing is hidden:
|
||||
* every review is on its mint page, and PROMOTE_MAX_AGE_S keeps "latest"
|
||||
* meaning latest.
|
||||
* The heading says "Latest reviews", so the order under it is the event
|
||||
* `created_at` and nothing else. This used to float reviews whose author had a
|
||||
* kind 0 to the front, which read as broken on the page: a named review from two
|
||||
* months ago sat between two reviews from this week, and the card feet said so,
|
||||
* because the "2mo ago" label is formatted from the very same `created_at` this
|
||||
* sorts on. Author names are still resolved and still shown — they just no longer
|
||||
* decide the order.
|
||||
*
|
||||
* Sorted here rather than left to the scan above, so that the invariant holds
|
||||
* whatever the gathering loop does later, and `id` breaks ties between two events
|
||||
* that share a second so two builds of the same events agree.
|
||||
*/
|
||||
const cutoff = Math.floor(Date.now() / 1000) - PROMOTE_MAX_AGE_S;
|
||||
const promoted = (review: BuildReview): number =>
|
||||
review.profile?.found && review.created_at >= cutoff ? 1 : 0;
|
||||
|
||||
candidates.sort((a, b) => promoted(b) - promoted(a) || b.created_at - a.created_at);
|
||||
candidates.sort((a, b) => b.created_at - a.created_at || a.id.localeCompare(b.id));
|
||||
|
||||
return candidates.slice(0, limit);
|
||||
} catch {
|
||||
|
||||
Reference in New Issue
Block a user