The game log component had only ever shown one player's turns, fine for the Daily Challenge but a mismatch for both duel modes, where a second player's words and fruit chips had nowhere to go. A wayfinder map, drilled out of an older PvP issue asking for a game log panel in the first place, locked a two-owner design: entries gain an optional owner, and the log mirrors itself, one side's chips growing rightward and the other's leftward, only when a log actually contains an opponent entry. Daily Challenge and every log recorded before this change keep the plain single-column layout unchanged.

AI Duel picked up the mirrored view first, the opponent's words and fruit routed through the same two chip-pushing helpers the player's own turns already used. PvP needed more: a batch endpoint to reconstruct history after a reload, since a resuming guest has no local memory of turns that happened before they arrived, and a builder that derives every chip from a turn's own stored data rather than a word's dictionary metadata, which the PvP client never has:

```typescript
export function buildPvpLogEntries(
  turn: Pick<PvpTurnRow, 'turnIndex' | 'word' | 'actor'> & { result: PvpTurnResult },
  viewerRole: 'host' | 'guest'
): GameLogEntry[] {
  const owner: DuelTurn = turn.actor === viewerRole ? 'player' : 'opponent';
  const { result } = turn;
  const eatenEdibles = result.eatenEdibles ?? [];
  // ...derives every remaining chip field from the turn's own stored data.
```

The issue that specified this half of the work, though, undersold its own point: it covered reconstructing history and widening the [end-of-game recap's log toggle](/posts/one-recap-two-modes) to PvP, but left out the actual live log panel on the page a PvP game is played on, which was the entire reason the original issue existed. Adding it meant raising the reserved chrome height to make room and re-verifying, across two real browser sessions playing against each other, that the on-screen keyboard stayed above the fold at phone width.

Working the PvP side surfaced a second, unrelated bug: the guest in a PvP game saw a length-multiplier badge in the UI that never actually multiplied their score. The engine had only ever applied the multiplier to its internal `player` actor, written back when the only kind of opponent was the AI, which was never supposed to get one, but PvP maps its guest onto that same `opponent` slot. One flag fixed it:

```typescript
function actorGetsLengthMultiplier(isPlayer: boolean, config: DuelGameConfig): boolean {
  return isPlayer || config.opponentMultiplierEnabled === true;
}
```

False for AI Duel, true for PvP, since a human guest deserves the same scoring the host gets. No historical leaderboard rows were recomputed; only final scores are stored, never a per-turn breakdown to recompute from, and the reasoning for leaving past games as they were is recorded directly on the bug's own issue.