split-relay.js
1.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
* 接力分配(2026-10-09 定:平分)。参与分配的人 = 最终提交者 + 所有留下过有效检查点后离开的前任
* (has_valid_checkpoint 且 end_reason ∈ timeout / released / transferred);同一 Agent 多次持有只算一份。
* 赏金按人数平分,除不尽的余数归最终提交者。各笔之和必须等于 reward。
*
* @param {number} reward 正整数
* @param {Array<{ agent_id: string, end_reason: 'submitted'|'released'|'timeout'|'transferred'|null, has_valid_checkpoint: boolean }>} holds 该任务的全部持有记录
* @param {string} final_agent_id 最终提交者
* @returns {Array<{ agent_id: string, amount: number, kind: 'winner'|'relay_share' }>} 最终提交者排第一
*/
export function splitRelayPayout(reward, holds, final_agent_id) {
if (!Number.isSafeInteger(reward) || reward < 1) throw new Error(`splitRelayPayout: reward invalid: ${reward}`)
const relays = new Set()
for (const hold of holds) {
switch (hold.end_reason) {
case 'released':
case 'timeout':
case 'transferred':
if (hold.has_valid_checkpoint && hold.agent_id !== final_agent_id) relays.add(hold.agent_id)
break
case 'submitted':
case null:
break
default:
throw new Error(`Unhandled end_reason: ${hold.end_reason}, agent: ${hold.agent_id}`)
}
}
const share = Math.floor(reward / (relays.size + 1))
// 人数多于积分时前任分不到整数份:全部归最终提交者(发放明细金额必须 > 0)。
const paidRelays = share === 0 ? [] : [...relays]
const payouts = [
{ agent_id: final_agent_id, amount: reward - share * paidRelays.length, kind: /** @type {const} */ ('winner') },
...paidRelays.map((agent_id) => ({ agent_id, amount: share, kind: /** @type {const} */ ('relay_share') })),
]
if (payouts.reduce((sum, payout) => sum + payout.amount, 0) !== reward) throw new Error(`splitRelayPayout: payouts do not sum to reward ${reward}`)
return payouts
}