From a4b9512c7ccd522dfa5fbba5956090f3859fc4d9 Mon Sep 17 00:00:00 2001 From: 777genius Date: Sat, 30 May 2026 10:15:07 +0300 Subject: [PATCH] perf: keep positive transcript team-affinity cached as files grow fileBelongsToTeam streams a transcript's head lines to decide if it belongs to a team, cached by (mtime,size). During launch the team's own session transcripts grow on every poll, invalidating the cache and forcing a re-stream + head re-parse each time (profiled at ~7-8% main-thread JS after the earlier fixes). A positive affinity is decided by early head lines that persist as an append-only transcript grows, so a true result stays valid while the file only grows. Reuse a cached true when size has not shrunk; a false result is still re-checked on any change (a short file may grow head lines mentioning the team) and a shrink forces a re-scan. Existing resolver tests still pass. --- .../team/TeamTranscriptProjectResolver.ts | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/main/services/team/TeamTranscriptProjectResolver.ts b/src/main/services/team/TeamTranscriptProjectResolver.ts index 7f88431c..15afbdc2 100644 --- a/src/main/services/team/TeamTranscriptProjectResolver.ts +++ b/src/main/services/team/TeamTranscriptProjectResolver.ts @@ -1021,8 +1021,19 @@ export class TeamTranscriptProjectResolver { const cacheKey = this.buildTeamAffinityFileCacheKey(filePath, normalizedTeam); const cached = this.teamAffinityFileCache.get(cacheKey); - if (cached && cached.mtimeMs === fileStat.mtimeMs && cached.size === fileStat.size) { - return cached.belongsToTeam; + if (cached) { + // A positive affinity is decided by early "head" lines that persist as an + // append-only transcript grows, so a `true` result stays valid while the file + // only grows (size >= cached). This avoids re-streaming the team's own + // continuously-growing transcripts on every bootstrap poll. A `false` result + // is still re-checked on any change, since a short file may later grow head + // lines that mention the team; a shrink (rewrite/truncate) also forces a re-scan. + if (cached.belongsToTeam && fileStat.size >= cached.size) { + return true; + } + if (cached.mtimeMs === fileStat.mtimeMs && cached.size === fileStat.size) { + return cached.belongsToTeam; + } } const stream = createReadStream(filePath, { encoding: 'utf8' });