const { test } = require('node:test'); const assert = require('node:assert/strict'); const { summarizeActorDisarmEvidence } = require('./actor-disarm-evidence.cjs'); const aura = (appliedAt = 100, sourceId = 'enemy') => ({ instanceId: 'tank:disarm', definitionId: 'enemy-source-spell-6713', sourceId, targetId: 'tank', appliedAt, expiresAt: appliedAt + 100 }); const event = (id, occurredAt, sourceActorId = 'tank', attackHand = 'mainhand') => ({ id, occurredAt, sourceActorId, kind: 'damage', attackHand, rawAmount: 20, effectiveAmount: 10 }); test('includes actual actor hand attempts with an exclusive expiry and preserves other actors separately', () => { const result = summarizeActorDisarmEvidence([event(1, 100), event(2, 199, 'tank', 'offhand'), event(3, 200), event(4, 150, 'enemy'), event(5, 150, 'player', 'ranged')], [{ observedAt: 100, auras: [aura()] }, { observedAt: 200, auras: [] }], 'player', ['tank']); assert.deepEqual(result.disarmWindows[0].handEvents.map((entry) => entry.id), [1, 2]); assert.deepEqual(result.actorHandEvents.map((entry) => entry.id), [1, 2, 3, 5]); }); test('early removal and refresh do not attribute later attacks to a stale full-duration aura', () => { const result = summarizeActorDisarmEvidence([event(1, 149), event(2, 150), event(3, 174), event(4, 175)], [{ observedAt: 100, auras: [aura()] }, { observedAt: 151, auras: [aura(150, 'other-enemy')] }, { observedAt: 175, auras: [] }], 'player', ['tank']); assert.deepEqual(result.disarmWindows.map((window) => ({ end: window.observedEndAt, reason: window.endEvidence, ids: window.handEvents.map((entry) => entry.id) })), [{ end: 150, reason: 'refresh', ids: [1] }, { end: 175, reason: 'committed-removal', ids: [2, 3] }]); });