```ts
/** Utilities over a nested thread of comments, scores and deletions. */

type ThreadComment = {
  score: number;
  deleted: boolean;
  replies: ThreadComment[];
};

/** Total score of the thread; deleted comments contribute nothing. */
export function threadScore(comment: ThreadComment): number {
  let total = comment.score;
  for (const reply of comment.replies) {
    const prunedReply = pruneDeleted(reply);
    if (prunedReply !== null) {
      total += threadScore(prunedReply);
    }
  }
  return total;
}

/** Depth of the deepest reply chain, 1 for a lone comment. */
export function threadDepth(comment: ThreadComment): number {
  let deepest = 0;
  for (const reply of comment.replies) {
    const depth = threadDepth(reply);
    if (depth > deepest) {
      deepest = depth;
    }
  }
  return deepest + 1;
}

/** How many live comments in the thread reach the awarding bar. */
export function countAwarded(comment: ThreadComment, minScore: number): number {
  let count = 0;
  if (!comment.deleted && comment.score >= minScore) {
    count = 1;
  }
  for (const reply of comment.replies) {
    count += countAwarded(pruneDeleted(reply), minScore);
  }
  return count;
}

/** A copy of the thread without childless deleted comments. */
export function pruneDeleted(comment: ThreadComment): ThreadComment | null {
  const kept: ThreadComment[] = [];
  for (const reply of comment.replies) {
    const prunedReply = pruneDeleted(reply);
    if (prunedReply !== null) {
      kept.push(prunedReply);
    }
  }
  if (comment.deleted && kept.length === 0) {
    return null;
  }
  return {
    score: comment.score,
    deleted: comment.deleted,
    replies: kept,
  };
}
```