Skip to content

Commit 8cbf3ce

Browse files
committed
fix(referrals): name Kilo Pass Impact reward unit
1 parent fcc9a0b commit 8cbf3ce

3 files changed

Lines changed: 30 additions & 11 deletions

File tree

.specs/impact-referrals.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Updated 2026-05-06 -- require Impact Advocate reward redemption after local Kilo
1818
Updated 2026-05-12 -- note price-versioned KiloClaw billing preserves referral semantics.
1919
Updated 2026-05-22 -- renamed to `.specs/impact-referrals.md` and expanded to Kilo Pass referrals.
2020
Updated 2026-05-28 -- classify enforced Stripe EFW refunds as adverse payments.
21+
Updated 2026-05-29 -- name the Impact-facing Kilo Pass reward unit `Kilo Pass Bonus Credits`.
2122

2223
## Conventions
2324

@@ -628,8 +629,8 @@ application, and Kilo Pass redeems after local referral bonus allocation.
628629
local reward eligibility, application, cancellation, or reversal.
629630

630631
158a. For Kilo Pass, when a local referral bonus reward is allocated/granted, the system MUST queue asynchronous Impact
631-
Advocate reward lookup and single-reward redemption using the reward amount and USD unit so Impact reporting
632-
matches Kilo allocation state.
632+
Advocate reward lookup and single-reward redemption using the USD-denominated reward amount and the
633+
`Kilo Pass Bonus Credits` unit so Impact reporting matches Kilo allocation state.
633634

634635
158b. Kilo Pass Impact Advocate reward redemption MUST be idempotently queued per local reward and MUST NOT block paid
635636
conversion processing, reward ledger creation, reward application, billing settlement, or user access.
@@ -772,6 +773,10 @@ application, and Kilo Pass redeems after local referral bonus allocation.
772773

773774
## Changelog
774775

776+
### 2026-05-29 -- Name the Kilo Pass Impact reward unit
777+
778+
Kilo Pass reward synchronization sends the `Kilo Pass Bonus Credits` unit to Impact Advocate while retaining the USD-denominated local reward amount.
779+
775780
### 2026-05-28 -- Enforced EFW refunds are adverse payments
776781

777782
Classified an enforced Stripe Early Fraud Warning refund as an adverse qualifying payment for both covered products. Pending or earned-but-unapplied rewards cancel, already-applied rewards require support review, and later refund or chargeback delivery must remain idempotent.

apps/web/src/lib/impact/kilo-pass-referrals.test.ts

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,16 @@ jest.mock('@/lib/impact/advocate', () => {
1818
sendImpactAdvocateRewardLookupPayload: jest.fn(async () => ({
1919
ok: true,
2020
statusCode: 200,
21-
rewards: [{ id: 'impact-kilo-pass-reward', type: 'CREDIT', amount: 24.5, unit: 'USD' }],
21+
rewards: [
22+
{
23+
id: 'impact-kilo-pass-reward',
24+
type: 'CREDIT',
25+
amount: 24.5,
26+
unit: 'Kilo Pass Bonus Credits',
27+
},
28+
],
2229
responseBody:
23-
'{"rewards":[{"id":"impact-kilo-pass-reward","type":"CREDIT","amount":24.5,"unit":"USD"}]}',
30+
'{"rewards":[{"id":"impact-kilo-pass-reward","type":"CREDIT","amount":24.5,"unit":"Kilo Pass Bonus Credits"}]}',
2431
})),
2532
sendImpactAdvocateRewardRedemptionPayload: jest.fn(async () => ({
2633
ok: true,
@@ -114,9 +121,16 @@ beforeEach(async () => {
114121
mockSendImpactAdvocateRewardLookupPayload.mockResolvedValue({
115122
ok: true,
116123
statusCode: 200,
117-
rewards: [{ id: 'impact-kilo-pass-reward', type: 'CREDIT', amount: 24.5, unit: 'USD' }],
124+
rewards: [
125+
{
126+
id: 'impact-kilo-pass-reward',
127+
type: 'CREDIT',
128+
amount: 24.5,
129+
unit: 'Kilo Pass Bonus Credits',
130+
},
131+
],
118132
responseBody:
119-
'{"rewards":[{"id":"impact-kilo-pass-reward","type":"CREDIT","amount":24.5,"unit":"USD"}]}',
133+
'{"rewards":[{"id":"impact-kilo-pass-reward","type":"CREDIT","amount":24.5,"unit":"Kilo Pass Bonus Credits"}]}',
120134
});
121135
mockSendImpactAdvocateRewardRedemptionPayload.mockResolvedValue({
122136
ok: true,
@@ -383,7 +397,7 @@ describe('Kilo Pass Impact referral conversions', () => {
383397
userId: 'referee@example.com',
384398
rewardTypeFilter: 'CREDIT',
385399
}),
386-
redemption: { amount: 24.5, unit: 'USD' },
400+
redemption: { amount: 24.5, unit: 'Kilo Pass Bonus Credits' },
387401
}),
388402
}),
389403
expect.objectContaining({
@@ -396,7 +410,7 @@ describe('Kilo Pass Impact referral conversions', () => {
396410
userId: 'referrer@example.com',
397411
rewardTypeFilter: 'CREDIT',
398412
}),
399-
redemption: { amount: 24.5, unit: 'USD' },
413+
redemption: { amount: 24.5, unit: 'Kilo Pass Bonus Credits' },
400414
}),
401415
}),
402416
])
@@ -413,7 +427,7 @@ describe('Kilo Pass Impact referral conversions', () => {
413427
{ programKey: ImpactAdvocateProgramKey.KiloPass }
414428
);
415429
expect(mockSendImpactAdvocateRewardRedemptionPayload).toHaveBeenCalledWith(
416-
{ rewardId: 'impact-kilo-pass-reward', amount: 24.5, unit: 'USD' },
430+
{ rewardId: 'impact-kilo-pass-reward', amount: 24.5, unit: 'Kilo Pass Bonus Credits' },
417431
{ programKey: ImpactAdvocateProgramKey.KiloPass }
418432
);
419433

@@ -837,7 +851,7 @@ describe('Kilo Pass Impact referral conversions', () => {
837851
state: 'redeemed',
838852
request_payload: expect.objectContaining({
839853
programKey: ImpactAdvocateProgramKey.KiloPass,
840-
redemption: { amount: 24.5, unit: 'USD' },
854+
redemption: { amount: 24.5, unit: 'Kilo Pass Bonus Credits' },
841855
}),
842856
})
843857
)

apps/web/src/lib/impact/kiloclaw-referrals.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ const REFERRAL_REWARD_ACTOR = {
129129

130130
const SIGNUP_REFERRAL_TOUCH_CAPTURE_GRACE_MS = 10 * 60 * 1000;
131131
const IMPACT_ADVOCATE_KILOCLAW_REWARD_UNIT = 'MONTH';
132-
const IMPACT_ADVOCATE_KILO_PASS_REWARD_UNIT = 'USD';
132+
const IMPACT_ADVOCATE_KILO_PASS_REWARD_UNIT = 'Kilo Pass Bonus Credits';
133133

134134
function getDatabaseClient(database?: DatabaseClient): DatabaseClient {
135135
return database ?? db;

0 commit comments

Comments
 (0)