mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-06 11:48:24 +00:00
feat(cli): skip republishing unchanged graperank cards
Previously `graperank --publish` rebuilt and rebroadcast a NIP-85 kind:30382 ContactCard for every scored user on every run, minting a new event id and created_at even when the rank was identical — pure churn for a parameterized- replaceable event. Read back the ranks we last published from the account's own kind:30382 cards in the local store (ctx.publish already persists them) and publish only the targets whose rank is new or changed. Report the count left alone as `skipped_unchanged`. Verified against a local geode relay: first run publishes N cards (skipped_unchanged=0); an immediate re-run with identical ranks publishes 0 (skipped_unchanged=N). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RWk2ZMrGBSr4WenKgwqmbB
This commit is contained in:
@@ -164,11 +164,22 @@ object GrapeRankCommand {
|
||||
?.takeIf { it.isNotEmpty() }
|
||||
?: ctx.outboxRelays()
|
||||
|
||||
val toPublish =
|
||||
// Ranks we've already published (read back from the store, which
|
||||
// holds our own prior cards) — keyed by target, newest per target.
|
||||
// Lets us leave an unchanged card alone instead of churning it.
|
||||
val publishedRanks = publishedCardRanks(ctx)
|
||||
|
||||
val candidates =
|
||||
ranked
|
||||
.filter { rankOf(it.value) >= minRank }
|
||||
.take(publishLimit)
|
||||
.map { it.key to rankOf(it.value) }
|
||||
val changed = candidates.filter { (target, rank) -> publishedRanks[target] != rank }
|
||||
val toPublish = changed.take(publishLimit)
|
||||
|
||||
result["skipped_unchanged"] = candidates.size - changed.size
|
||||
if (changed.size > toPublish.size) {
|
||||
result["publish_truncated"] = changed.size - toPublish.size
|
||||
}
|
||||
|
||||
if (relays.isEmpty()) {
|
||||
result["published"] = 0
|
||||
@@ -240,6 +251,25 @@ object GrapeRankCommand {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The rank we last published for each target, read from the active account's
|
||||
* own kind:30382 cards in the local store (newest card wins per target).
|
||||
* `ctx.publish` stores every card it sends, so on repeat runs this reflects
|
||||
* what's already out there and lets us skip targets whose rank is unchanged.
|
||||
*/
|
||||
private suspend fun publishedCardRanks(ctx: Context): Map<HexKey, Int> {
|
||||
val self = ctx.identity.pubKeyHex
|
||||
return ctx.store
|
||||
.query<Event>(Filter(kinds = listOf(ContactCardEvent.KIND), authors = listOf(self)))
|
||||
.filterIsInstance<ContactCardEvent>()
|
||||
.groupBy { it.aboutUser() }
|
||||
.mapNotNull { (target, cards) ->
|
||||
val t = target ?: return@mapNotNull null
|
||||
val rank = cards.maxByOrNull { it.createdAt }?.rank() ?: return@mapNotNull null
|
||||
t to rank
|
||||
}.toMap()
|
||||
}
|
||||
|
||||
/** Build + publish one NIP-85 kind:30382 card per user, bounded-concurrently. */
|
||||
private suspend fun publishCards(
|
||||
ctx: Context,
|
||||
|
||||
Reference in New Issue
Block a user