[playersettings] Drop Growth.YIR telemetry and MakerPenSessionCount on write (#145)

* [playersettings] drop Growth.YIR telemetry on write

The client posts its Year-In-Review counters (Growth.YIR.UGC.TubeDistance,
Growth.YIR.DistanceTraveled, …) through PUT /playersettings with a new value every time,
so the change-detection dedupe never skips them. A two-minute tail at ~500 CCU showed
them as about half of all KV writes (3.7 writes/s overall, 448 writes from 448 PUTs).
Nothing server-side reads them and the client has none for a new player, so a PUT naming
one is answered 200 and nothing is stored. Keys stay unseeded for a player whose only
posts are telemetry.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* [playersettings] also drop MakerPenSessionCount

A per-session counter the client bumps on every post, like the Growth.YIR telemetry; nothing
reads it. The maker pen PREFERENCES (MakerPen_SnappingMode and the other MakerPen_* keys) are
kept — the client reads those back.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
devin
2026-10-26 23:47:04 -04:00
committed by GitHub
parent f6214fb824
commit 619b4c772c
4 changed files with 66 additions and 3 deletions
@@ -164,6 +164,42 @@ describe('playersettings endpoints', () => {
)
})
it('PUT /playersettings drops Growth.YIR and MakerPenSessionCount without writing', async () => {
const stored = '{ "PlayerSessionCount": "5" }'
await env.RECFLARE_PLAYER_SETTINGS.put('player:11', stored)
const form = await SELF.fetch(
`${ORIGIN}/playersettings`,
putForm({ key: 'Growth.YIR.UGC.TubeDistance', value: '1234.5' }, await bearer('11'))
)
expect(form.status).toBe(200)
expect(await env.RECFLARE_PLAYER_SETTINGS.get('player:11', 'text')).toBe(stored)
// A JSON batch keeps the real settings (a maker pen PREFERENCE included) and drops
// only the telemetry and the session counter.
const json = await SELF.fetch(`${ORIGIN}/playersettings`, {
method: 'PUT',
headers: { 'content-type': 'application/json', ...(await bearer('11')) },
body: JSON.stringify([
{ key: 'Growth.YIR.DistanceTraveled', value: '99' },
{ key: 'MakerPenSessionCount', value: '3' },
{ key: 'MakerPen_SnappingMode', value: '2' },
]),
})
expect(json.status).toBe(200)
expect(await env.RECFLARE_PLAYER_SETTINGS.get('player:11', 'json')).toEqual({
PlayerSessionCount: '5',
MakerPen_SnappingMode: '2',
})
// A player with nothing stored stays unseeded: no key is created for telemetry alone.
await SELF.fetch(
`${ORIGIN}/playersettings`,
putForm({ key: 'Growth.YIR.TimeSpentWithFriends', value: '7' }, await bearer('12'))
)
expect(await env.RECFLARE_PLAYER_SETTINGS.get('player:12', 'text')).toBeNull()
})
it('PUT /playersettings 200s with no parseable settings', async () => {
const res = await SELF.fetch(`${ORIGIN}/playersettings`, putForm({}, await bearer('9')))
expect(res.status).toBe(200)