import Foundation import Testing @testable import Prowl extension PerformanceBenchmarks { /// Pins the #650/#657 fragment cache: a poll whose transcript tails are /// unchanged must not pay tail reads, JSON parsing, and normalization again. /// Cold rounds rebuild a fresh `TranscriptFragmentCache` per call — the /// pre-#650 per-poll cost — while warm rounds reuse one cache the way /// `AgentSessionResolver` does across its 300 ms polls. @Suite struct SessionScoringBenchmarks { @Test func warmFragmentCacheOutpacesColdReparsingPerPoll() throws { let fileManager = FileManager.default let tempRoot = fileManager.temporaryDirectory.appending(path: UUID().uuidString) defer { try? fileManager.removeItem(at: tempRoot) } try fileManager.createDirectory(at: tempRoot, withIntermediateDirectories: true) let marker = "the quick brown benchmark fox jumps over the lazy resolver dog" let sessionCount = 6 let linesPerTranscript = BenchmarkMeasurement.isFullMode ? 400 : 100 var candidates: [AgentSessionCandidate] = [] for sessionIndex in 0..= 3, "warm fragment cache was only \(BenchmarkMeasurement.ratio(medians))x cold re-parsing" ) } } } /// `bestMatch` takes the cache `inout`; a closure cannot capture `inout` state, /// so the warm cache lives in a reference box instead. private final class FragmentCacheBox { var cache = TranscriptFragmentCache() }