@rine-kit/pubg-intelligence 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/LICENSE +21 -0
  2. package/dist/src/analytics.d.ts +176 -0
  3. package/dist/src/analytics.js +431 -0
  4. package/dist/src/analytics.js.map +1 -0
  5. package/dist/src/assistant.d.ts +87 -0
  6. package/dist/src/assistant.js +310 -0
  7. package/dist/src/assistant.js.map +1 -0
  8. package/dist/src/battle.d.ts +280 -0
  9. package/dist/src/battle.js +1249 -0
  10. package/dist/src/battle.js.map +1 -0
  11. package/dist/src/combat-long.d.ts +42 -0
  12. package/dist/src/combat-long.js +146 -0
  13. package/dist/src/combat-long.js.map +1 -0
  14. package/dist/src/combat-quality.d.ts +101 -0
  15. package/dist/src/combat-quality.js +253 -0
  16. package/dist/src/combat-quality.js.map +1 -0
  17. package/dist/src/evaluation-fixtures.d.ts +13 -0
  18. package/dist/src/evaluation-fixtures.js +144 -0
  19. package/dist/src/evaluation-fixtures.js.map +1 -0
  20. package/dist/src/evaluation-replay.d.ts +5 -0
  21. package/dist/src/evaluation-replay.js +107 -0
  22. package/dist/src/evaluation-replay.js.map +1 -0
  23. package/dist/src/evaluation.d.ts +140 -0
  24. package/dist/src/evaluation.js +180 -0
  25. package/dist/src/evaluation.js.map +1 -0
  26. package/dist/src/experiment-store.d.ts +56 -0
  27. package/dist/src/experiment-store.js +159 -0
  28. package/dist/src/experiment-store.js.map +1 -0
  29. package/dist/src/field.d.ts +103 -0
  30. package/dist/src/field.js +298 -0
  31. package/dist/src/field.js.map +1 -0
  32. package/dist/src/fights.d.ts +89 -0
  33. package/dist/src/fights.js +238 -0
  34. package/dist/src/fights.js.map +1 -0
  35. package/dist/src/highlights.d.ts +44 -0
  36. package/dist/src/highlights.js +153 -0
  37. package/dist/src/highlights.js.map +1 -0
  38. package/dist/src/index.d.ts +24 -0
  39. package/dist/src/index.js +25 -0
  40. package/dist/src/index.js.map +1 -0
  41. package/dist/src/insights.d.ts +44 -0
  42. package/dist/src/insights.js +343 -0
  43. package/dist/src/insights.js.map +1 -0
  44. package/dist/src/intent.d.ts +40 -0
  45. package/dist/src/intent.js +119 -0
  46. package/dist/src/intent.js.map +1 -0
  47. package/dist/src/landing.d.ts +74 -0
  48. package/dist/src/landing.js +195 -0
  49. package/dist/src/landing.js.map +1 -0
  50. package/dist/src/lobby.d.ts +48 -0
  51. package/dist/src/lobby.js +209 -0
  52. package/dist/src/lobby.js.map +1 -0
  53. package/dist/src/match-insight.d.ts +165 -0
  54. package/dist/src/match-insight.js +542 -0
  55. package/dist/src/match-insight.js.map +1 -0
  56. package/dist/src/match-relative.d.ts +73 -0
  57. package/dist/src/match-relative.js +145 -0
  58. package/dist/src/match-relative.js.map +1 -0
  59. package/dist/src/match-story.d.ts +155 -0
  60. package/dist/src/match-story.js +636 -0
  61. package/dist/src/match-story.js.map +1 -0
  62. package/dist/src/profiles.d.ts +41 -0
  63. package/dist/src/profiles.js +136 -0
  64. package/dist/src/profiles.js.map +1 -0
  65. package/dist/src/raw-telemetry-archive.d.ts +29 -0
  66. package/dist/src/raw-telemetry-archive.js +340 -0
  67. package/dist/src/raw-telemetry-archive.js.map +1 -0
  68. package/dist/src/raw-telemetry-backfill.d.ts +28 -0
  69. package/dist/src/raw-telemetry-backfill.js +144 -0
  70. package/dist/src/raw-telemetry-backfill.js.map +1 -0
  71. package/dist/src/research.d.ts +89 -0
  72. package/dist/src/research.js +376 -0
  73. package/dist/src/research.js.map +1 -0
  74. package/dist/src/rhythm.d.ts +104 -0
  75. package/dist/src/rhythm.js +260 -0
  76. package/dist/src/rhythm.js.map +1 -0
  77. package/dist/src/streaks.d.ts +117 -0
  78. package/dist/src/streaks.js +367 -0
  79. package/dist/src/streaks.js.map +1 -0
  80. package/dist/src/style.d.ts +304 -0
  81. package/dist/src/style.js +1461 -0
  82. package/dist/src/style.js.map +1 -0
  83. package/dist/src/tactics.d.ts +88 -0
  84. package/dist/src/tactics.js +1221 -0
  85. package/dist/src/tactics.js.map +1 -0
  86. package/package.json +49 -3
  87. package/README.md +0 -3
@@ -0,0 +1,253 @@
1
+ import { median, normalizeWeaponName, wilsonInterval } from './analytics.js';
2
+ export const COMBAT_QUALITY_SCHEMA_VERSION = 1;
3
+ export function emptyCombatQuality() {
4
+ return {
5
+ groups: 0,
6
+ firstKnockFor: 0,
7
+ firstKnockAgainst: 0,
8
+ leadHeld: 0,
9
+ leadLost: 0,
10
+ followUpObserved: 0,
11
+ followUpMissed: 0,
12
+ followUpSeconds: [],
13
+ knockedChains: 0,
14
+ knockedRevived: 0,
15
+ knockedKilled: 0,
16
+ reviveSeconds: [],
17
+ downedChains: 0,
18
+ downedFinished: 0,
19
+ finishSeconds: [],
20
+ thirdPartyAgainstUs: 0,
21
+ thirdPartyByUs: 0,
22
+ };
23
+ }
24
+ export function analyzeCombatQuality(result) {
25
+ const stats = emptyCombatQuality();
26
+ const trackedTeams = new Set();
27
+ const trackedPlayers = new Set();
28
+ for (const episode of result.episodes) {
29
+ for (const team of episode.teams) {
30
+ if (!team.tracked || !team.teamRef)
31
+ continue;
32
+ trackedTeams.add(team.teamRef);
33
+ for (const ref of team.memberRefs)
34
+ trackedPlayers.add(ref);
35
+ }
36
+ }
37
+ if (!trackedTeams.size)
38
+ return stats;
39
+ const seenChains = new Set();
40
+ for (const episode of result.episodes) {
41
+ for (const chain of episode.knockChains) {
42
+ if (seenChains.has(chain.knockEventId))
43
+ continue;
44
+ seenChains.add(chain.knockEventId);
45
+ const victimOurs = chain.knockedPlayerRef !== null && trackedPlayers.has(chain.knockedPlayerRef);
46
+ const attackerOurs = chain.attackerRef !== null && trackedPlayers.has(chain.attackerRef);
47
+ if (victimOurs && !attackerOurs) {
48
+ stats.knockedChains += 1;
49
+ if (chain.outcome === 'REVIVE') {
50
+ stats.knockedRevived += 1;
51
+ if (chain.elapsedSeconds !== null)
52
+ stats.reviveSeconds.push(chain.elapsedSeconds);
53
+ }
54
+ else if (chain.outcome === 'KILL')
55
+ stats.knockedKilled += 1;
56
+ }
57
+ else if (attackerOurs && !victimOurs) {
58
+ stats.downedChains += 1;
59
+ if (chain.outcome === 'KILL') {
60
+ stats.downedFinished += 1;
61
+ if (chain.elapsedSeconds !== null)
62
+ stats.finishSeconds.push(chain.elapsedSeconds);
63
+ }
64
+ }
65
+ }
66
+ }
67
+ for (const group of result.battles) {
68
+ if (!group.teamRefs.some((ref) => trackedTeams.has(ref)))
69
+ continue;
70
+ stats.groups += 1;
71
+ const firstId = group.postKnockResponse.firstKnockEventId;
72
+ const first = firstId
73
+ ? group.timeline.find((event) => event.sourceEventId === firstId)
74
+ : undefined;
75
+ const weFirst = first?.actorTeamRef ? trackedTeams.has(first.actorTeamRef) : false;
76
+ const theyFirst = first?.victimTeamRef ? trackedTeams.has(first.victimTeamRef) : false;
77
+ if (weFirst) {
78
+ stats.firstKnockFor += 1;
79
+ const resolution = group.firstKnockAdvantage?.resolution;
80
+ if (resolution === 'ongoing')
81
+ stats.leadHeld += 1;
82
+ else if (resolution === 'equalized' || resolution === 'reversed')
83
+ stats.leadLost += 1;
84
+ if (group.postKnockResponse.status === 'observed') {
85
+ stats.followUpObserved += 1;
86
+ if (group.postKnockResponse.elapsedSeconds !== null)
87
+ stats.followUpSeconds.push(group.postKnockResponse.elapsedSeconds);
88
+ }
89
+ else if (group.postKnockResponse.status === 'not_observed_in_window')
90
+ stats.followUpMissed += 1;
91
+ }
92
+ else if (theyFirst) {
93
+ stats.firstKnockAgainst += 1;
94
+ }
95
+ for (const party of group.possibleThirdParty) {
96
+ if (trackedTeams.has(party.teamRef))
97
+ stats.thirdPartyByUs += 1;
98
+ else
99
+ stats.thirdPartyAgainstUs += 1;
100
+ }
101
+ }
102
+ return stats;
103
+ }
104
+ export function summarizeCombatQuality(items) {
105
+ const sum = (pick) => items.reduce((total, item) => total + pick(item), 0);
106
+ const all = (pick) => items.flatMap(pick);
107
+ const firstFor = sum((item) => item.firstKnockFor);
108
+ const firstAgainst = sum((item) => item.firstKnockAgainst);
109
+ const held = sum((item) => item.leadHeld);
110
+ const lost = sum((item) => item.leadLost);
111
+ const knocked = sum((item) => item.knockedChains);
112
+ const revived = sum((item) => item.knockedRevived);
113
+ const killed = sum((item) => item.knockedKilled);
114
+ const downed = sum((item) => item.downedChains);
115
+ const finished = sum((item) => item.downedFinished);
116
+ const groups = sum((item) => item.groups);
117
+ const againstUs = sum((item) => item.thirdPartyAgainstUs);
118
+ return {
119
+ schemaVersion: COMBAT_QUALITY_SCHEMA_VERSION,
120
+ matches: items.length,
121
+ groups,
122
+ firstKnock: {
123
+ forUs: firstFor,
124
+ againstUs: firstAgainst,
125
+ ourRate: wilsonInterval(firstFor, firstFor + firstAgainst),
126
+ },
127
+ leadConversion: { held, lost, heldRate: wilsonInterval(held, held + lost) },
128
+ followUp: {
129
+ observed: sum((item) => item.followUpObserved),
130
+ missed: sum((item) => item.followUpMissed),
131
+ medianSeconds: median(all((item) => item.followUpSeconds)),
132
+ },
133
+ revive: {
134
+ knocked,
135
+ revived,
136
+ killed,
137
+ unresolved: knocked - revived - killed,
138
+ reviveRate: wilsonInterval(revived, knocked),
139
+ medianSeconds: median(all((item) => item.reviveSeconds)),
140
+ },
141
+ finish: {
142
+ downed,
143
+ finished,
144
+ finishRate: wilsonInterval(finished, downed),
145
+ medianSeconds: median(all((item) => item.finishSeconds)),
146
+ },
147
+ thirdParty: {
148
+ againstUs,
149
+ byUs: sum((item) => item.thirdPartyByUs),
150
+ againstRate: wilsonInterval(againstUs, groups),
151
+ },
152
+ notes: [
153
+ '只统计已归档遥测中观察到的交战;队伍成员按观察到的事件识别,不推断完整花名册。',
154
+ '「第三方介入」是时间重叠的候选,不代表对方意图;「首倒优势保持」按观察到的倒地数平衡计算。',
155
+ '未解决的倒地链表示窗口内没有观察到救起或击杀。',
156
+ ],
157
+ };
158
+ }
159
+ export const DEATH_STAGES = ['开局', '中期', '后期', '决赛圈'];
160
+ /** Stage from the number of teams still alive when a squad member died. */
161
+ export function deathStageOf(aliveTeams) {
162
+ if (aliveTeams === null)
163
+ return '未知';
164
+ if (aliveTeams >= 20)
165
+ return '开局';
166
+ if (aliveTeams >= 10)
167
+ return '中期';
168
+ if (aliveTeams >= 5)
169
+ return '后期';
170
+ return '决赛圈';
171
+ }
172
+ export function analyzeDeaths(telemetry, trackedPlayerIds) {
173
+ const tracked = new Set(trackedPlayerIds);
174
+ if (!tracked.size)
175
+ return [];
176
+ const samples = telemetry.circleSamples
177
+ .filter((sample) => sample.phase === 'in_match' && sample.timeSeconds !== null && sample.aliveTeams !== null)
178
+ .sort((left, right) => left.timeSeconds - right.timeSeconds);
179
+ const aliveTeamsAt = (time) => {
180
+ if (time === null)
181
+ return null;
182
+ let found = null;
183
+ for (const sample of samples) {
184
+ if (sample.timeSeconds > time)
185
+ break;
186
+ found = sample.aliveTeams;
187
+ }
188
+ return found;
189
+ };
190
+ const knocked = new Set(telemetry.events
191
+ .filter((event) => event.type === 'KNOCK' && event.victimId && tracked.has(event.victimId))
192
+ .map((event) => `${event.victimId}:${event.dbnoId ?? ''}`));
193
+ const seen = new Set();
194
+ const kills = telemetry.events
195
+ .filter((event) => event.type === 'KILL' &&
196
+ event.victimId !== null &&
197
+ tracked.has(event.victimId) &&
198
+ event.phase !== 'pre_match')
199
+ .sort((left, right) => (left.timeSeconds ?? Infinity) - (right.timeSeconds ?? Infinity));
200
+ const records = [];
201
+ for (const event of kills) {
202
+ if (seen.has(event.victimId))
203
+ continue;
204
+ seen.add(event.victimId);
205
+ const weapon = event.weaponId ? normalizeWeaponName(event.weaponId) : null;
206
+ records.push({
207
+ stage: deathStageOf(aliveTeamsAt(event.timeSeconds)),
208
+ weapon,
209
+ afterKnock: event.dbnoId !== null && knocked.has(`${event.victimId}:${event.dbnoId}`),
210
+ squadWipe: false,
211
+ });
212
+ }
213
+ if (records.length && records.length >= tracked.size)
214
+ records[records.length - 1].squadWipe = true;
215
+ return records;
216
+ }
217
+ export function summarizeDeaths(records) {
218
+ const stages = new Map();
219
+ const wipes = new Map();
220
+ const weapons = new Map();
221
+ let unknownWeapon = 0;
222
+ for (const record of records) {
223
+ stages.set(record.stage, (stages.get(record.stage) ?? 0) + 1);
224
+ if (record.squadWipe)
225
+ wipes.set(record.stage, (wipes.get(record.stage) ?? 0) + 1);
226
+ if (record.weapon)
227
+ weapons.set(record.weapon, (weapons.get(record.weapon) ?? 0) + 1);
228
+ else
229
+ unknownWeapon += 1;
230
+ }
231
+ const order = [...DEATH_STAGES, '未知'];
232
+ const afterKnock = records.filter((record) => record.afterKnock).length;
233
+ return {
234
+ deaths: records.length,
235
+ afterKnock: { count: afterKnock, rate: wilsonInterval(afterKnock, records.length) },
236
+ stages: order
237
+ .filter((stage) => stages.has(stage))
238
+ .map((stage) => ({
239
+ stage,
240
+ deaths: stages.get(stage),
241
+ share: stages.get(stage) / records.length,
242
+ })),
243
+ wipeStages: order
244
+ .filter((stage) => wipes.has(stage))
245
+ .map((stage) => ({ stage, wipes: wipes.get(stage) })),
246
+ weapons: [...weapons.entries()]
247
+ .map(([weapon, deaths]) => ({ weapon, deaths }))
248
+ .sort((left, right) => right.deaths - left.deaths || left.weapon.localeCompare(right.weapon))
249
+ .slice(0, 8),
250
+ unknownWeapon,
251
+ };
252
+ }
253
+ //# sourceMappingURL=combat-quality.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"combat-quality.js","sourceRoot":"","sources":["../../src/combat-quality.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { NormalizedMatch } from '@rine-kit/pubg-domain';
2
+ import type { BenchmarkSplit } from './evaluation.js';
3
+ export interface TacticalBenchmarkFixtureCase {
4
+ caseId: string;
5
+ split: BenchmarkSplit;
6
+ stratum: string;
7
+ expectedFirstKnockBySquad: boolean | null;
8
+ match: NormalizedMatch;
9
+ trackedPlayerIds: string[];
10
+ telemetryPayload: unknown[];
11
+ }
12
+ /** Synthetic identities and telemetry; holdout is split by whole match case. */
13
+ export declare function createTacticalBenchmarkFixtures(): TacticalBenchmarkFixtureCase[];
@@ -0,0 +1,144 @@
1
+ const trackedOne = { accountId: 'squad-member-a', teamId: 'squad-team' };
2
+ const trackedTwo = { accountId: 'squad-member-b', teamId: 'squad-team' };
3
+ const opponentOne = { accountId: 'opponent-member-a', teamId: 'opponent-team' };
4
+ const opponentTwo = { accountId: 'opponent-member-b', teamId: 'opponent-team' };
5
+ function knock(seconds, attacker, victim, dbnoId) {
6
+ return {
7
+ _T: 'LogPlayerMakeGroggy',
8
+ ...(seconds === null
9
+ ? {}
10
+ : { _D: new Date(Date.parse('2026-10-01T12:00:00.000Z') + seconds * 1000).toISOString() }),
11
+ common: { isGame: true },
12
+ attacker,
13
+ victim,
14
+ dBNOId: dbnoId,
15
+ };
16
+ }
17
+ function damage(seconds, attacker, victim) {
18
+ return {
19
+ _T: 'LogPlayerTakeDamage',
20
+ _D: new Date(Date.parse('2026-10-01T12:00:00.000Z') + seconds * 1000).toISOString(),
21
+ common: { isGame: true },
22
+ attacker,
23
+ victim,
24
+ damage: 20,
25
+ };
26
+ }
27
+ function fixtureCase(input) {
28
+ const timestamp = Date.parse('2026-10-01T12:00:00.000Z');
29
+ const player = (accountId, displayName) => ({
30
+ accountId,
31
+ playerName: displayName,
32
+ displayName,
33
+ rank: 8,
34
+ kills: 1,
35
+ assists: 0,
36
+ damage: 80,
37
+ dbnos: 1,
38
+ revives: 0,
39
+ headshotKills: 0,
40
+ survivalTime: 800,
41
+ longestKill: 0,
42
+ deaths: 1,
43
+ deathSemantics: 'explicit',
44
+ });
45
+ const match = {
46
+ schemaVersion: 3,
47
+ matchId: input.caseId,
48
+ shard: 'fixture',
49
+ createdAt: new Date(timestamp).toISOString(),
50
+ timestamp,
51
+ matchType: 'competitive',
52
+ gameMode: 'squad-fpp',
53
+ isCompetitive: true,
54
+ mapName: 'Sanitized Training Range',
55
+ duration: 900,
56
+ patchVersion: 'fixture',
57
+ players: [player(trackedOne.accountId, 'SQUAD_A'), player(trackedTwo.accountId, 'SQUAD_B')],
58
+ };
59
+ return {
60
+ caseId: input.caseId,
61
+ split: input.split,
62
+ stratum: input.stratum,
63
+ expectedFirstKnockBySquad: input.expected,
64
+ match,
65
+ trackedPlayerIds: [trackedOne.accountId, trackedTwo.accountId],
66
+ telemetryPayload: input.events,
67
+ };
68
+ }
69
+ /** Synthetic identities and telemetry; holdout is split by whole match case. */
70
+ export function createTacticalBenchmarkFixtures() {
71
+ return [
72
+ fixtureCase({
73
+ caseId: 'r4-dev-positive-01',
74
+ split: 'development',
75
+ stratum: 'clear-squad-first-knock',
76
+ expected: true,
77
+ events: [
78
+ knock(5, trackedOne, opponentOne, 'fixture-dbno-01'),
79
+ damage(8, trackedTwo, opponentOne),
80
+ ],
81
+ }),
82
+ fixtureCase({
83
+ caseId: 'r4-dev-negative-01',
84
+ split: 'development',
85
+ stratum: 'opponent-first-then-squad-knock',
86
+ expected: false,
87
+ events: [
88
+ knock(5, opponentOne, trackedOne, 'fixture-dbno-02'),
89
+ knock(11, trackedOne, opponentOne, 'fixture-dbno-03'),
90
+ ],
91
+ }),
92
+ fixtureCase({
93
+ caseId: 'r4-dev-unresolved-01',
94
+ split: 'development',
95
+ stratum: 'no-knock-opportunity',
96
+ expected: null,
97
+ events: [damage(5, trackedOne, opponentOne)],
98
+ }),
99
+ fixtureCase({
100
+ caseId: 'r4-holdout-positive-01',
101
+ split: 'holdout',
102
+ stratum: 'clear-squad-first-knock',
103
+ expected: true,
104
+ events: [knock(7, trackedTwo, opponentTwo, 'fixture-dbno-04')],
105
+ }),
106
+ fixtureCase({
107
+ caseId: 'r4-holdout-negative-01',
108
+ split: 'holdout',
109
+ stratum: 'opponent-first-then-squad-knock',
110
+ expected: false,
111
+ events: [
112
+ knock(4, opponentTwo, trackedTwo, 'fixture-dbno-05'),
113
+ knock(9, trackedOne, opponentTwo, 'fixture-dbno-06'),
114
+ ],
115
+ }),
116
+ fixtureCase({
117
+ caseId: 'r4-holdout-negative-02',
118
+ split: 'holdout',
119
+ stratum: 'opponent-only-knock',
120
+ expected: false,
121
+ events: [knock(10, opponentOne, trackedOne, 'fixture-dbno-07')],
122
+ }),
123
+ fixtureCase({
124
+ caseId: 'r4-holdout-unresolved-01',
125
+ split: 'holdout',
126
+ stratum: 'unknown-timestamp',
127
+ expected: null,
128
+ events: [
129
+ knock(null, trackedOne, opponentOne, 'fixture-dbno-08'),
130
+ knock(13, opponentTwo, trackedTwo, 'fixture-dbno-09'),
131
+ ],
132
+ }),
133
+ fixtureCase({
134
+ caseId: 'r4-holdout-unresolved-02',
135
+ split: 'holdout',
136
+ stratum: 'missing-team-attribution',
137
+ expected: null,
138
+ events: [
139
+ knock(12, { accountId: trackedOne.accountId }, { accountId: 'opponent-member-unknown' }, 'fixture-dbno-10'),
140
+ ],
141
+ }),
142
+ ];
143
+ }
144
+ //# sourceMappingURL=evaluation-fixtures.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluation-fixtures.js","sourceRoot":"","sources":["../../src/evaluation-fixtures.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { type EvaluationExperimentReport } from './evaluation.js';
2
+ export declare const R4_BENCHMARK_DATASET_ID: "pubg-intelligence-r4-first-knock-fixtures-v1";
3
+ export declare const R4_BASELINE_VERSION: "legacy-any-tracked-knock-v0";
4
+ export declare const R4_CANDIDATE_VERSION: "tactical-social-rules-v2";
5
+ export declare function replayTacticalBenchmark(): EvaluationExperimentReport;
@@ -0,0 +1,107 @@
1
+ import { BATTLE_RECONSTRUCTION_PARSER_VERSION, normalizeBattleTelemetry, reconstructBattleEpisodes, } from './battle.js';
2
+ import { analyzeTacticalMatch, TACTICAL_RULE_VERSION } from './tactics.js';
3
+ import { buildEvaluationExperiment, fingerprintBenchmarkDataset, } from './evaluation.js';
4
+ import { renderResearchTemplate } from './assistant.js';
5
+ import { createTacticalBenchmarkFixtures } from './evaluation-fixtures.js';
6
+ export const R4_BENCHMARK_DATASET_ID = 'pubg-intelligence-r4-first-knock-fixtures-v1';
7
+ export const R4_BASELINE_VERSION = 'legacy-any-tracked-knock-v0';
8
+ export const R4_CANDIDATE_VERSION = TACTICAL_RULE_VERSION;
9
+ function evidenceRefs(refs) {
10
+ return refs.map((ref) => ({
11
+ matchId: ref.matchId,
12
+ eventId: ref.eventId,
13
+ timeSeconds: ref.timeSeconds,
14
+ kind: ref.kind,
15
+ }));
16
+ }
17
+ export function replayTacticalBenchmark() {
18
+ const startedAt = new Date().toISOString();
19
+ const start = performance.now();
20
+ const memoryBefore = process.memoryUsage();
21
+ const fixtures = createTacticalBenchmarkFixtures();
22
+ const predictions = fixtures.map((fixture) => {
23
+ const telemetry = normalizeBattleTelemetry(fixture.telemetryPayload, fixture.match);
24
+ const reconstruction = reconstructBattleEpisodes({
25
+ match: fixture.match,
26
+ telemetry,
27
+ trackedPlayerIds: fixture.trackedPlayerIds,
28
+ });
29
+ const analysis = analyzeTacticalMatch({
30
+ match: fixture.match,
31
+ telemetry,
32
+ reconstruction,
33
+ trackedPlayerIds: fixture.trackedPlayerIds,
34
+ });
35
+ const candidate = analysis.candidates.find((row) => row.ruleId === 'combat.first-knock-share');
36
+ if (!candidate)
37
+ throw new Error('benchmark_candidate_rule_missing');
38
+ const tracked = new Set(fixture.trackedPlayerIds);
39
+ const trackedKnocks = telemetry.events.filter((event) => event.type === 'KNOCK' && event.actorId !== null && tracked.has(event.actorId));
40
+ const baselineEvidence = trackedKnocks.map((event) => ({
41
+ matchId: fixture.match.matchId,
42
+ eventId: event.sourceEventId,
43
+ timeSeconds: event.timeSeconds,
44
+ kind: 'legacy-any-tracked-knock',
45
+ }));
46
+ return {
47
+ caseId: fixture.caseId,
48
+ split: fixture.split,
49
+ stratum: fixture.stratum,
50
+ expected: fixture.expectedFirstKnockBySquad,
51
+ baseline: trackedKnocks.length > 0,
52
+ candidate: candidate.metric.numerator === null ? null : candidate.metric.numerator > 0,
53
+ baselineEvidence,
54
+ candidateEvidence: evidenceRefs([...candidate.supportEvents, ...candidate.counterexamples]),
55
+ };
56
+ });
57
+ const datasetFingerprint = fingerprintBenchmarkDataset({
58
+ id: R4_BENCHMARK_DATASET_ID,
59
+ cases: fixtures.map(({ caseId, split, stratum, expectedFirstKnockBySquad, match, trackedPlayerIds, telemetryPayload, }) => ({
60
+ caseId,
61
+ split,
62
+ stratum,
63
+ expectedFirstKnockBySquad,
64
+ match,
65
+ trackedPlayerIds,
66
+ telemetryPayload,
67
+ })),
68
+ });
69
+ const factualTemplateText = '3 matches, 500 average damage, 2 knock conversions.';
70
+ const templates = ['tactical_coaching', 'squad_humor', 'chronological_story'];
71
+ const templateOutputs = templates.map((template) => renderResearchTemplate(template, factualTemplateText));
72
+ const numbersIn = (value) => value.match(/(?<![\p{L}\p{N}])\d[\d,]*(?:\.\d+)?%?/gu) ?? [];
73
+ const expectedNumbers = numbersIn(factualTemplateText);
74
+ const memoryAfter = process.memoryUsage();
75
+ return buildEvaluationExperiment({
76
+ experimentName: 'R4 first-knock baseline versus episode-aware rule',
77
+ datasetId: R4_BENCHMARK_DATASET_ID,
78
+ datasetFingerprint,
79
+ ruleId: 'combat.first-knock-share',
80
+ baselineVersion: R4_BASELINE_VERSION,
81
+ candidateVersion: R4_CANDIDATE_VERSION,
82
+ parserVersion: BATTLE_RECONSTRUCTION_PARSER_VERSION,
83
+ thresholds: {
84
+ ruleId: 'combat.first-knock-share',
85
+ baseline: 'any tracked KNOCK event in match',
86
+ candidate: 'tracked attacker of the first knock in an R1 episode',
87
+ contactGapSeconds: 28,
88
+ missingTimestamp: 'unresolved',
89
+ },
90
+ startedAt,
91
+ runtimeMs: performance.now() - start,
92
+ resourceUsage: {
93
+ heapUsedBytesBefore: memoryBefore.heapUsed,
94
+ heapUsedBytesAfter: memoryAfter.heapUsed,
95
+ heapUsedDeltaBytes: memoryAfter.heapUsed - memoryBefore.heapUsed,
96
+ rssBytesAfter: memoryAfter.rss,
97
+ },
98
+ templateEvaluation: {
99
+ templateCount: templates.length,
100
+ numericFactParity: templateOutputs.every((output) => JSON.stringify(numbersIn(output)) === JSON.stringify(expectedNumbers)),
101
+ uniqueWordingCount: new Set(templateOutputs).size,
102
+ humanPreferenceLabels: 0,
103
+ },
104
+ predictions,
105
+ });
106
+ }
107
+ //# sourceMappingURL=evaluation-replay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluation-replay.js","sourceRoot":"","sources":["../../src/evaluation-replay.ts"],"names":[],"mappings":"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"}