fix(#26): apply decay before score mutations in recordSuccess/recordFailure

Previously recordSuccess/recordFailure read identity.trustScore (raw stored value)
and incremented/decremented from there. Long-absent identities could instantly
recover their pre-absence tier on the first interaction, defeating decay.

Fix: both methods now call applyDecay(identity) first to get the true current
baseline, then apply the score delta from there before persisting.
This commit is contained in:
Replit Agent
2026-03-19 16:11:36 +00:00
parent aed011c6e4
commit b0ac398cf2

View File

@@ -129,9 +129,12 @@ export class TrustService {
}
// Called after a successful (paid) interaction.
// Decay is applied first so long-absent identities start from their decayed
// baseline rather than the raw stored score.
async recordSuccess(pubkey: string, satsCost: number): Promise<void> {
const identity = await this.getOrCreate(pubkey);
const newScore = identity.trustScore + SCORE_PER_SUCCESS;
const decayedBase = applyDecay(identity);
const newScore = decayedBase + SCORE_PER_SUCCESS;
const newTier = computeTier(newScore);
await db
@@ -147,6 +150,7 @@ export class TrustService {
logger.info("trust: success recorded", {
pubkey: pubkey.slice(0, 8),
decayedBase,
newScore,
newTier,
satsCost,
@@ -154,9 +158,11 @@ export class TrustService {
}
// Called after a failed, rejected, or abusive interaction.
// Decay is applied first so mutations always start from the current true baseline.
async recordFailure(pubkey: string, reason: string): Promise<void> {
const identity = await this.getOrCreate(pubkey);
const newScore = Math.max(0, identity.trustScore - SCORE_PER_FAILURE);
const decayedBase = applyDecay(identity);
const newScore = Math.max(0, decayedBase - SCORE_PER_FAILURE);
const newTier = computeTier(newScore);
await db
@@ -172,6 +178,7 @@ export class TrustService {
logger.info("trust: failure recorded", {
pubkey: pubkey.slice(0, 8),
decayedBase,
newScore,
newTier,
reason,