feat(renown): add the Renown power-curve table and reputation-rank resolver
This commit is contained in:
33
apps/api/src/reputation/reputation-rank.spec.ts
Normal file
33
apps/api/src/reputation/reputation-rank.spec.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { resolveReputationRank } from './reputation-rank';
|
||||
|
||||
describe('resolveReputationRank', () => {
|
||||
it('resolves 0 reputation to Stranger with a next threshold of 100', () => {
|
||||
expect(resolveReputationRank(0)).toEqual({
|
||||
key: 'STRANGER',
|
||||
label: 'Fremder',
|
||||
threshold: 0,
|
||||
nextThreshold: 100,
|
||||
});
|
||||
});
|
||||
|
||||
it('resolves exactly at a threshold to that rank, not the one below', () => {
|
||||
expect(resolveReputationRank(100).key).toBe('TOLERATED');
|
||||
expect(resolveReputationRank(99).key).toBe('STRANGER');
|
||||
});
|
||||
|
||||
it('resolves every documented threshold to its exact rank', () => {
|
||||
expect(resolveReputationRank(250).key).toBe('KNOWN');
|
||||
expect(resolveReputationRank(500).key).toBe('RECOGNIZED');
|
||||
expect(resolveReputationRank(800).key).toBe('TRUSTED');
|
||||
expect(resolveReputationRank(1200).key).toBe('ESTEEMED');
|
||||
});
|
||||
|
||||
it('has no next threshold once at the top rank', () => {
|
||||
expect(resolveReputationRank(1200).nextThreshold).toBeNull();
|
||||
expect(resolveReputationRank(50_000).nextThreshold).toBeNull();
|
||||
});
|
||||
|
||||
it('reports the correct nextThreshold mid-range', () => {
|
||||
expect(resolveReputationRank(300).nextThreshold).toBe(500);
|
||||
});
|
||||
});
|
||||
30
apps/api/src/reputation/reputation-rank.ts
Normal file
30
apps/api/src/reputation/reputation-rank.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
export interface ReputationRankInfo {
|
||||
key: string;
|
||||
label: string;
|
||||
threshold: number;
|
||||
nextThreshold: number | null;
|
||||
}
|
||||
|
||||
// Verbatim thresholds from spec §10, German labels for the German-language UI.
|
||||
// Sorted descending: the first entry whose threshold <= reputation wins.
|
||||
const REPUTATION_RANKS: ReadonlyArray<{ threshold: number; key: string; label: string }> = [
|
||||
{ threshold: 1200, key: 'ESTEEMED', label: 'Geachtet' },
|
||||
{ threshold: 800, key: 'TRUSTED', label: 'Vertraut' },
|
||||
{ threshold: 500, key: 'RECOGNIZED', label: 'Anerkannt' },
|
||||
{ threshold: 250, key: 'KNOWN', label: 'Bekannt' },
|
||||
{ threshold: 100, key: 'TOLERATED', label: 'Geduldet' },
|
||||
{ threshold: 0, key: 'STRANGER', label: 'Fremder' },
|
||||
];
|
||||
|
||||
export function resolveReputationRank(reputation: number): ReputationRankInfo {
|
||||
const index = REPUTATION_RANKS.findIndex((rank) => reputation >= rank.threshold);
|
||||
const rank = REPUTATION_RANKS[index];
|
||||
const nextRank = index > 0 ? REPUTATION_RANKS[index - 1] : null;
|
||||
|
||||
return {
|
||||
key: rank.key,
|
||||
label: rank.label,
|
||||
threshold: rank.threshold,
|
||||
nextThreshold: nextRank ? nextRank.threshold : null,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user