feat(replay/enrichment): fix TS build, align annotations with §8.3

- Fix TS6133: rename _matchId → matchId in AnnotationOverlay and use
  this.matchId in filter so the field is actually read
- Align ANNOTATION_TAGS in feedback.ts to four types from plan §8.3:
  insight, mistake, idea, highlight (matching components/annotation.ts)
- Update LS_KEY to acb_annotations_v2 to avoid stale-format conflicts
- Fix duplicate import block in api-types.ts (re-exported evolution types)
- Remove unused debugPanelChevron ref in replay.ts; add annotation
  imports for AnnotationOverlay and createAnnotationForm

The AI commentary generation backend (enrichment.go) and client-side
subtitle display (replay-viewer.ts, embed.ts, home.ts) were already
complete in prior commits.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
jedarden 2026-04-21 17:20:22 -04:00
parent d8812b98ee
commit 30f2c63b20
4 changed files with 26 additions and 29 deletions

View file

@ -99,23 +99,6 @@ export interface RegisterResponse {
}
// Evolution dashboard types (re-exported from types.ts for convenience)
import type {
LiveJSON,
EvolutionIslandStat,
EvolutionParentInfo,
EvolutionStageResult,
EvolutionValidationStatus,
EvaluationMatchResult,
EvolutionEvaluationStatus,
EvolutionCandidate,
EvolutionCycleInfo,
EvolutionActivityEntry,
EvolutionTotals,
EvolutionGenerationEntry,
EvolutionLineageNode,
EvolutionMetaSnapshot,
} from './types';
export type {
LiveJSON,
EvolutionIslandStat as IslandStat,
@ -134,6 +117,7 @@ export type {
} from './types';
// Convenience alias: the full live.json document
import type { LiveJSON } from './types';
export type EvolutionLiveData = LiveJSON;
// Full island stat (legacy format, not in live.json schema)

View file

@ -93,7 +93,7 @@ export class AnnotationOverlay {
private annotations: Annotation[] = [];
private currentTurn: number = 0;
private totalTurns: number = 0;
private _matchId: string = '';
private matchId: string = '';
private options: AnnotationOverlayOptions;
constructor(container: HTMLElement, options: AnnotationOverlayOptions = {}) {
@ -104,7 +104,7 @@ export class AnnotationOverlay {
loadAnnotations(matchId: string, annotations: Annotation[], totalTurns: number): void {
this.matchId = matchId;
this.totalTurns = totalTurns;
this.annotations = annotations.filter(a => a.match_id === matchId);
this.annotations = annotations.filter(a => a.match_id === this.matchId);
this.render();
}

View file

@ -1,19 +1,19 @@
// Community replay feedback: users annotate replay turns with tags.
// Annotations feed the evolution pipeline by surfacing interesting moments.
// Types consolidated to match plan §8.3 replay_feedback schema.
import { fetchMatchIndex, API_BASE, type MatchSummary } from '../api-types';
import { ReplayViewer } from '../replay-viewer';
import type { Replay } from '../types';
// ─── Types ────────────────────────────────────────────────────────────────────
// Aligned with plan §8.3: insight, mistake, idea, highlight
export const ANNOTATION_TAGS = [
{ id: 'turning_point', label: 'Turning Point', color: '#ef4444', desc: 'A moment that decisively changed the outcome' },
{ id: 'tactical_insight', label: 'Tactical Insight', color: '#3b82f6', desc: 'A clever or instructive strategy in action' },
{ id: 'impressive', label: 'Impressive', color: '#a78bfa', desc: 'Exceptional performance or execution' },
{ id: 'funny', label: 'Funny', color: '#f59e0b', desc: 'An unexpected or humorous sequence' },
{ id: 'bug', label: 'Possible Bug', color: '#f97316', desc: 'Behaviour that looks unintended' },
{ id: 'evolution_seed', label: 'Evolution Seed', color: '#22c55e', desc: 'A sequence worth propagating in the evolution pipeline' },
{ id: 'insight', label: 'Tactical Insight', color: '#3b82f6', desc: 'A clever or instructive strategy in action' },
{ id: 'mistake', label: 'Mistake Spotted', color: '#ef4444', desc: 'Behaviour that looks unintended or suboptimal' },
{ id: 'idea', label: 'Strategy Idea', color: '#22c55e', desc: 'A novel approach worth propagating in the evolution pipeline' },
{ id: 'highlight', label: 'Highlight', color: '#fbbf24', desc: 'An impressive or noteworthy moment' },
];
export interface ReplayAnnotation {
@ -415,13 +415,13 @@ function initFeedback(): void {
// ─── Local storage for offline annotations ────────────────────────────────────
const LS_KEY = 'acb_annotations';
const LS_KEY = 'acb_annotations_v2';
function saveLocalAnnotation(ann: ReplayAnnotation): void {
try {
const existing: ReplayAnnotation[] = JSON.parse(localStorage.getItem(LS_KEY) ?? '[]');
existing.push(ann);
localStorage.setItem(LS_KEY, JSON.stringify(existing.slice(-200))); // keep last 200
localStorage.setItem(LS_KEY, JSON.stringify(existing.slice(-200)));
} catch {}
}

View file

@ -1,6 +1,14 @@
// Standalone replay viewer page - lazy loaded from app.ts
import type { Replay, GameEvent, DebugInfo } from '../types';
import type { Replay, GameEvent, DebugInfo, Position } from '../types';
import { fetchCommentary } from '../api-types';
import {
AnnotationOverlay,
createAnnotationForm,
fetchFeedback,
loadLocalAnnotations,
ANNOTATION_OVERLAY_STYLES,
type Annotation,
} from '../components/annotation';
const loadReplayViewer = () => import('../replay-viewer');
@ -170,6 +178,12 @@ function initReplayViewerWithClass(ReplayViewerClass: any, initialUrl?: string):
</div>
</div>
<div class="panel annotation-panel" id="annotation-panel">
<h2>Annotations</h2>
<div id="annotation-overlay-container"></div>
<div id="annotation-form-container"></div>
</div>
<div class="keyboard-shortcuts">
<kbd>Space</kbd> Play/Pause
<kbd></kbd><kbd></kbd> Step
@ -347,7 +361,6 @@ function initReplayViewer(ReplayViewerClass: any, initialUrl?: string): void {
const commentaryToggle = document.getElementById('commentary-toggle') as HTMLButtonElement;
const debugPanel = document.getElementById('debug-panel') as HTMLDivElement;
const debugPanelToggleBtn = document.getElementById('debug-panel-toggle-btn') as HTMLDivElement;
const debugPanelChevron = document.getElementById('debug-panel-chevron') as HTMLSpanElement;
const debugPlayerToggles = document.getElementById('debug-player-toggles') as HTMLDivElement;
const debugInfoDisplay = document.getElementById('debug-info-display') as HTMLDivElement;