Skip to content

feat: add support for mistral#161

Merged
hanrw merged 3 commits intotddworks:mainfrom
farmdawgnation:msf/mistral-support-3wx
Mar 22, 2026
Merged

feat: add support for mistral#161
hanrw merged 3 commits intotddworks:mainfrom
farmdawgnation:msf/mistral-support-3wx

Conversation

@farmdawgnation
Copy link
Copy Markdown
Contributor

@farmdawgnation farmdawgnation commented Mar 22, 2026

Disclaimer: I'm a Swift n00b. I know enough to review the code Claude generated and assert it doesn't have anything obviously wild going on, but I would not be surprised if something slipped by.

This PR adds support for Mistral as a provider for ClaudeBar. Because Mistral doesn't provide an elegant way to check the current rate limiting (at least, not one that I've been able to find), I opted for just representing what the current API spend and token usage actually is from Mistral Vibe session logs available on the local filesystem. Welcome any and all feedback here. This would (clearly) not represent any impact from outside Mistral usage (e.g. OpenCode, LeChat, etc).

Summary by CodeRabbit

  • New Features

    • Added Mistral AI provider with integrated usage monitoring and real-time status tracking.
  • Improvements

    • Daily working time metrics now display conditionally based on actual usage data availability.
  • Tests

    • Added comprehensive test coverage for Mistral provider integration and session analysis.

farmdawgnation and others added 3 commits March 21, 2026 21:06
  Adds a Mistral provider that reads Vibe session log files from
  ~/.vibe/logs/session/*/metadata.json to report daily token usage
  and estimated cost using Devstral pricing ($0.40/M input, $2.00/M output).

  No API key or network access required. isAvailable() returns true when
  the Vibe session log directory exists (i.e. Vibe is installed).
  probe() returns a UsageSnapshot with CostUsage and DailyUsageReport.

  Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Adds a log-only Mistral provider that reads ~/.vibe/logs/session/*/meta.json
  to report daily token usage and estimated cost using Devstral pricing
  ($0.40/M input tokens, $2.00/M output tokens).

  No API key or network access is required. isAvailable() returns true when
  the Vibe session log directory exists (i.e. Vibe is installed). probe()
  returns a UsageSnapshot with a DailyUsageReport only — no CostUsage or
  quota data, since Mistral doesn't expose useful quota information via API.

  Key implementation details:
  - Vibe session directories use UTC timestamps in their names
    (session_YYYYMMDD_HHMMSS_sessionid); parsing now uses the full
    date+time component with UTC timezone to correctly classify sessions
    that cross UTC midnight into the right local calendar day
  - Session metadata is in meta.json (not metadata.json)
  - Working time is not tracked (Vibe logs don't include wall-clock duration)
  - Working time card in MenuContentView is gated on workingTime > 0

  Removes MistralSettingsRepository sub-protocol and all conformances
  (JSONSettingsRepository, UserDefaultsProviderSettingsRepository) since
  no API key storage is needed. MistralProvider now uses the base
  ProviderSettingsRepository.

  Branding: uses cat.fill SF Symbol as the provider switcher icon.

  Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
…elds

Switches the Vibe session log analyzer from computing token totals and
cost from raw prompt/completion token counts to reading the pre-aggregated
session_total_llm_tokens and session_cost fields directly from meta.json.

Removes the inputPricePerMToken and outputPricePerMToken constants.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 22, 2026

📝 Walkthrough

Walkthrough

A new AI provider for Mistral has been integrated into the application, including provider implementation, usage tracking via Vibe session log analysis, visual identity configuration, UI conditional rendering, app wiring, and comprehensive test coverage.

Changes

Cohort / File(s) Summary
Core Mistral Provider Implementation
Sources/Domain/Provider/Mistral/MistralProvider.swift, Sources/Infrastructure/Mistral/MistralUsageProbe.swift, Sources/Infrastructure/Mistral/VibeSessionLogAnalyzer.swift
Added MistralProvider (observable, AIProvider-conforming class) with persisted enablement state, URL properties, and refresh logic. Added MistralUsageProbe to probe Vibe session logs for availability and usage. Added VibeSessionLogAnalyzer to parse Vibe session directories, extract token counts and costs from meta.json, and aggregate daily usage reports.
Integration and Visualization
Sources/App/ClaudeBarApp.swift, Sources/App/Views/ProviderVisualIdentity.swift
Wired MistralProvider into app initialization with MistralUsageProbe and shared settings. Extended ProviderVisualIdentity for Mistral with cat.fill symbol, MistralIcon asset reference, brand orange theme color (distinct for dark/light schemes), and two-color linear gradient.
Assets
Sources/App/Resources/Assets.xcassets/MistralIcon.imageset/Contents.json
Added Xcode asset metadata for MistralIcon.imageset with three resolution renditions (1x, 2x, 3x).
UI Updates
Sources/App/Views/MenuContentView.swift
Made daily usage card rendering for .workingTime metric conditional—now shown only when today or previous period has non-zero working time.
Test Suite
Tests/InfrastructureTests/Mistral/MistralUsageProbeTests.swift, Tests/InfrastructureTests/Mistral/VibeSessionLogAnalyzerTests.swift
Added comprehensive async test suites for MistralUsageProbe (availability checking, snapshot generation, error handling) and VibeSessionLogAnalyzer (session parsing, token aggregation, date windowing, malformed file resilience, cost calculation).
Minor Updates
Tests/InfrastructureTests/Settings/JSONSettingsRepositoryProviderTests.swift
Added trailing blank line.

Sequence Diagram

sequenceDiagram
    actor App as ClaudeBarApp
    participant Provider as MistralProvider
    participant Probe as MistralUsageProbe
    participant Analyzer as VibeSessionLogAnalyzer
    participant FS as File System

    App->>Provider: Initialize with MistralUsageProbe + SettingsRepository
    Provider->>Provider: Load isEnabled from SettingsRepository
    
    App->>Provider: Call refresh()
    Provider->>Provider: Set isSyncing = true
    Provider->>Probe: probe()
    
    Probe->>FS: Check ~/.vibe/logs/session exists
    alt Directory Exists
        Probe->>Analyzer: analyzeToday()
        Analyzer->>FS: List session directories (session_YYYYMMDD_*)
        Analyzer->>FS: Read meta.json from each session
        Analyzer->>Analyzer: Parse timestamps, aggregate tokens/costs
        Analyzer->>Analyzer: Split into today vs previous periods
        Analyzer-->>Probe: Return DailyUsageReport
        Probe-->>Provider: Return UsageSnapshot with report
    else Directory Missing
        Probe-->>Provider: Return empty UsageSnapshot
    end
    
    Provider->>Provider: Update snapshot, set isSyncing = false
    Provider->>SettingsRepository: Persist isEnabled state if changed
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 Whiskers twitch with glee, a cat-faced friend appears!
Mistral joins the fray, through log-analyzed years,
Session tokens counted, costs in gradients of light,
The burrow glows with orange now—oh, what a sight!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 37.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add support for mistral' directly and clearly summarizes the main change: adding Mistral as a new provider to the ClaudeBar application.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

CodeRabbit can generate a title for your PR based on the changes.

Add @coderabbitai placeholder anywhere in the title of your PR and CodeRabbit will replace it with a title based on the changes in the PR. You can change the placeholder by changing the reviews.auto_title_placeholder setting.

@farmdawgnation farmdawgnation changed the title Msf/mistral support 3wx feat: add support for mistral Mar 22, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (2)
Tests/InfrastructureTests/Mistral/VibeSessionLogAnalyzerTests.swift (1)

58-97: Make date-bound tests deterministic with fixed now and UTC calendar.

Using Date() and Calendar.current in “today/yesterday” tests can become flaky around local day boundaries.

🧪 Deterministic test setup example
+        var utcCalendar = Calendar(identifier: .gregorian)
+        utcCalendar.timeZone = TimeZone(secondsFromGMT: 0)!
+        let fixedNow = Date(timeIntervalSince1970: 1_710_000_000) // stable reference point
+
         let analyzer = VibeSessionLogAnalyzer(
             vibeSessionsDir: tempDir,
-            now: { Date() }
+            calendar: utcCalendar,
+            now: { fixedNow }
         )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Tests/InfrastructureTests/Mistral/VibeSessionLogAnalyzerTests.swift` around
lines 58 - 97, The tests use Date() and Calendar.current which can be flaky;
make them deterministic by passing a fixed now value (e.g. let fixedNow =
Date(timeIntervalSince1970: 1_700_000_000)) into the VibeSessionLogAnalyzer now
closure and by creating yesterday/today dates using a UTC calendar (let utc =
Calendar(identifier: .gregorian); utc.timeZone = TimeZone(secondsFromGMT: 0)!)
instead of Calendar.current; update the two tests to call makeSessionDir(in:
tempDir, date: fixedNow, suffix: ...) for today and use utc.date(byAdding: .day,
value: -1, to: fixedNow) for yesterday so analyzeToday() and the `#expect`
assertions are stable.
Sources/Domain/Provider/Mistral/MistralProvider.swift (1)

49-54: Avoid duplicating the provider id string in initialization.

Line 53 hardcodes "mistral" even though Line 11 already defines the canonical id. Keeping one source of truth reduces drift risk.

♻️ Suggested refactor
 public final class MistralProvider: AIProvider, `@unchecked` Sendable {
+    private static let providerId = "mistral"
+
-    public let id: String = "mistral"
+    public let id: String = Self.providerId
@@
-        self.isEnabled = settingsRepository.isEnabled(forProvider: "mistral", defaultValue: false)
+        self.isEnabled = settingsRepository.isEnabled(forProvider: Self.providerId, defaultValue: false)
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/Domain/Provider/Mistral/MistralProvider.swift` around lines 49 - 54,
The init currently hardcodes "mistral" when calling
settingsRepository.isEnabled; change it to use the provider's canonical id
constant instead (e.g., replace the literal with Self.id or MistralProvider.id)
so the provider id is sourced from the single canonical symbol defined at the
top of the type (ensure the static/constant identifier used matches the existing
declaration).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Sources/Domain/Provider/Mistral/MistralProvider.swift`:
- Line 8: The MistralProvider's refresh() has unsynchronized shared state
(isSyncing, snapshot, lastError) causing races when invoked concurrently; update
MistralProvider to serialize refresh executions—either make refresh()
actor-isolated (convert MistralProvider to an actor or move refresh into a
dedicated actor/serial Task) or add an atomic in-flight counter/lock to ensure
only one refresh runs at a time and only that execution flips isSyncing and
updates snapshot/lastError; remove or narrow use of `@unchecked` Sendable if
converting to an actor, and ensure defer { isSyncing = false } runs only for the
owning execution (use counter decrement or actor-isolation) so state remains
consistent.

In `@Sources/Infrastructure/Mistral/MistralUsageProbe.swift`:
- Around line 4-6: Update the top comment in MistralUsageProbe (the probe
implementation) to reflect the current data source and pricing: replace
references to "~/.vibe/logs/session/*/metadata.json" with
"~/.vibe/logs/session/*/meta.json" and replace "Devstral pricing" with
"analyzer-produced totals from session meta.json" (or similar wording) so the
docstring matches the actual behavior of MistralUsageProbe.

In `@Sources/Infrastructure/Mistral/VibeSessionLogAnalyzer.swift`:
- Around line 81-83: The session scanner currently only checks for "meta.json"
and skips folders that instead contain "metadata.json"; update the logic in
VibeSessionLogAnalyzer (the loop that builds metadataURL and uses
fileManager.fileExists) to look for both filenames: first try
entry.appendingPathComponent("meta.json"), and if that does not exist, try
entry.appendingPathComponent("metadata.json"); use the first existing URL (or
continue only if neither exists) so sessions written as "metadata.json" are
included in totals.

In `@Tests/InfrastructureTests/Mistral/MistralUsageProbeTests.swift`:
- Around line 61-76: The test in MistralUsageProbeTests named `probe returns
UsageSnapshot with costUsage and dailyUsageReport` contradicts its assertions
(it expects costUsage == nil); rename the test function to reflect that
costUsage is nil (for example `probe returns UsageSnapshot with no costUsage and
dailyUsageReport`) by changing the `@Test` func name in the MistralUsageProbeTests
class where `probe returns UsageSnapshot with costUsage and dailyUsageReport` is
declared, keeping the body (mock setup, creation of MistralUsageProbe, and
assertions) unchanged so test intent matches its assertions.

---

Nitpick comments:
In `@Sources/Domain/Provider/Mistral/MistralProvider.swift`:
- Around line 49-54: The init currently hardcodes "mistral" when calling
settingsRepository.isEnabled; change it to use the provider's canonical id
constant instead (e.g., replace the literal with Self.id or MistralProvider.id)
so the provider id is sourced from the single canonical symbol defined at the
top of the type (ensure the static/constant identifier used matches the existing
declaration).

In `@Tests/InfrastructureTests/Mistral/VibeSessionLogAnalyzerTests.swift`:
- Around line 58-97: The tests use Date() and Calendar.current which can be
flaky; make them deterministic by passing a fixed now value (e.g. let fixedNow =
Date(timeIntervalSince1970: 1_700_000_000)) into the VibeSessionLogAnalyzer now
closure and by creating yesterday/today dates using a UTC calendar (let utc =
Calendar(identifier: .gregorian); utc.timeZone = TimeZone(secondsFromGMT: 0)!)
instead of Calendar.current; update the two tests to call makeSessionDir(in:
tempDir, date: fixedNow, suffix: ...) for today and use utc.date(byAdding: .day,
value: -1, to: fixedNow) for yesterday so analyzeToday() and the `#expect`
assertions are stable.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 60c6e25d-2d7f-4178-a537-3a68133ba5b8

📥 Commits

Reviewing files that changed from the base of the PR and between 6c9699a and 6958374.

⛔ Files ignored due to path filters (3)
  • Sources/App/Resources/Assets.xcassets/MistralIcon.imageset/mistral_128.png is excluded by !**/*.png
  • Sources/App/Resources/Assets.xcassets/MistralIcon.imageset/mistral_192.png is excluded by !**/*.png
  • Sources/App/Resources/Assets.xcassets/MistralIcon.imageset/mistral_64.png is excluded by !**/*.png
📒 Files selected for processing (10)
  • Sources/App/ClaudeBarApp.swift
  • Sources/App/Resources/Assets.xcassets/MistralIcon.imageset/Contents.json
  • Sources/App/Views/MenuContentView.swift
  • Sources/App/Views/ProviderVisualIdentity.swift
  • Sources/Domain/Provider/Mistral/MistralProvider.swift
  • Sources/Infrastructure/Mistral/MistralUsageProbe.swift
  • Sources/Infrastructure/Mistral/VibeSessionLogAnalyzer.swift
  • Tests/InfrastructureTests/Mistral/MistralUsageProbeTests.swift
  • Tests/InfrastructureTests/Mistral/VibeSessionLogAnalyzerTests.swift
  • Tests/InfrastructureTests/Settings/JSONSettingsRepositoryProviderTests.swift

/// Observable class with its own state (isSyncing, snapshot, error).
/// Owns its probe and manages its own data lifecycle.
@Observable
public final class MistralProvider: AIProvider, @unchecked Sendable {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Verify whether provider refreshes can be triggered concurrently.
# Expected: identify call-sites using Task/task groups or overlapping refresh orchestration.

rg -nP --type=swift -C3 '\brefresh\s*\(' Sources
rg -nP --type=swift -C3 'Task\s*\{|async let|withTaskGroup' Sources
rg -nP --type=swift -C3 '\bisSyncing\b' Sources

Repository: tddworks/ClaudeBar

Length of output: 50374


Concurrent refresh() calls can leave state inconsistent: isSyncing and snapshot lack synchronization.

@unchecked Sendable permits concurrent access, and call sites in MenuContentView (lines 755–760, 769–782) use withTaskGroup and Task { ... } to invoke refresh(). While a guard check exists at line 776 (guard !provider.isSyncing else { return }), it creates a race condition: between the check and the actual call, another task may start refreshing. Once concurrent calls are in flight, the defer { isSyncing = false } only marks completion of the last one, leaving the state flag inconsistent with actual ongoing work. The same applies to unsynchronized writes to snapshot and lastError.

Serialize refresh state updates—e.g., actor-gate the method or use an atomic in-flight counter—to prevent overlapping refresh executions.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/Domain/Provider/Mistral/MistralProvider.swift` at line 8, The
MistralProvider's refresh() has unsynchronized shared state (isSyncing,
snapshot, lastError) causing races when invoked concurrently; update
MistralProvider to serialize refresh executions—either make refresh()
actor-isolated (convert MistralProvider to an actor or move refresh into a
dedicated actor/serial Task) or add an atomic in-flight counter/lock to ensure
only one refresh runs at a time and only that execution flips isSyncing and
updates snapshot/lastError; remove or narrow use of `@unchecked` Sendable if
converting to an actor, and ensure defer { isSyncing = false } runs only for the
owning execution (use counter decrement or actor-isolation) so state remains
consistent.

Comment on lines +4 to +6
/// Probes Vibe session logs for daily cost and token usage.
/// Reads from ~/.vibe/logs/session/*/metadata.json using Devstral pricing.
///
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Update stale probe docs to match current data source.

Line [5] says metadata.json and Devstral pricing, but implementation now uses analyzer-produced totals from meta.json session metadata. Please align comments with actual behavior.

✏️ Suggested doc fix
-/// Reads from ~/.vibe/logs/session/*/metadata.json using Devstral pricing.
+/// Reads from ~/.vibe/logs/session/*/meta.json and uses Vibe-provided
+/// aggregated `session_total_llm_tokens` and `session_cost` values.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/// Probes Vibe session logs for daily cost and token usage.
/// Reads from ~/.vibe/logs/session/*/metadata.json using Devstral pricing.
///
/// Probes Vibe session logs for daily cost and token usage.
/// Reads from ~/.vibe/logs/session/*/meta.json and uses Vibe-provided
/// aggregated `session_total_llm_tokens` and `session_cost` values.
///
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/Infrastructure/Mistral/MistralUsageProbe.swift` around lines 4 - 6,
Update the top comment in MistralUsageProbe (the probe implementation) to
reflect the current data source and pricing: replace references to
"~/.vibe/logs/session/*/metadata.json" with "~/.vibe/logs/session/*/meta.json"
and replace "Devstral pricing" with "analyzer-produced totals from session
meta.json" (or similar wording) so the docstring matches the actual behavior of
MistralUsageProbe.

Comment on lines +81 to +83
let metadataURL = entry.appendingPathComponent("meta.json")
guard fileManager.fileExists(atPath: metadataURL.path) else { continue }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Handle both meta.json and metadata.json session files.

Line [81] currently requires only meta.json. If a Vibe install writes metadata.json, sessions are silently skipped, causing incorrect usage/cost totals.

🔧 Compatibility fix
-            let metadataURL = entry.appendingPathComponent("meta.json")
-            guard fileManager.fileExists(atPath: metadataURL.path) else { continue }
+            let metadataCandidates = ["meta.json", "metadata.json"]
+            guard let metadataURL = metadataCandidates
+                .map({ entry.appendingPathComponent($0) })
+                .first(where: { fileManager.fileExists(atPath: $0.path) }) else { continue }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let metadataURL = entry.appendingPathComponent("meta.json")
guard fileManager.fileExists(atPath: metadataURL.path) else { continue }
let metadataCandidates = ["meta.json", "metadata.json"]
guard let metadataURL = metadataCandidates
.map({ entry.appendingPathComponent($0) })
.first(where: { fileManager.fileExists(atPath: $0.path) }) else { continue }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/Infrastructure/Mistral/VibeSessionLogAnalyzer.swift` around lines 81
- 83, The session scanner currently only checks for "meta.json" and skips
folders that instead contain "metadata.json"; update the logic in
VibeSessionLogAnalyzer (the loop that builds metadataURL and uses
fileManager.fileExists) to look for both filenames: first try
entry.appendingPathComponent("meta.json"), and if that does not exist, try
entry.appendingPathComponent("metadata.json"); use the first existing URL (or
continue only if neither exists) so sessions written as "metadata.json" are
included in totals.

Comment on lines +61 to +76
@Test func `probe returns UsageSnapshot with costUsage and dailyUsageReport`() async throws {
let mockAnalyzer = MockDailyUsageAnalyzing()
let report = makeReport()
given(mockAnalyzer)
.analyzeToday()
.willReturn(report)

let probe = MistralUsageProbe(vibeLogAnalyzer: mockAnalyzer)

let snapshot = try await probe.probe()

#expect(snapshot.providerId == "mistral")
#expect(snapshot.quotas.isEmpty)
#expect(snapshot.costUsage == nil)
#expect(snapshot.dailyUsageReport != nil)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Rename test to match its actual assertion.

Line [61] says “with costUsage”, but Line [74] asserts costUsage == nil. Rename for clarity.

✏️ Suggested rename
-    `@Test` func `probe returns UsageSnapshot with costUsage and dailyUsageReport`() async throws {
+    `@Test` func `probe returns UsageSnapshot with dailyUsageReport and no costUsage`() async throws {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Tests/InfrastructureTests/Mistral/MistralUsageProbeTests.swift` around lines
61 - 76, The test in MistralUsageProbeTests named `probe returns UsageSnapshot
with costUsage and dailyUsageReport` contradicts its assertions (it expects
costUsage == nil); rename the test function to reflect that costUsage is nil
(for example `probe returns UsageSnapshot with no costUsage and
dailyUsageReport`) by changing the `@Test` func name in the MistralUsageProbeTests
class where `probe returns UsageSnapshot with costUsage and dailyUsageReport` is
declared, keeping the body (mock setup, creation of MistralUsageProbe, and
assertions) unchanged so test intent matches its assertions.

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 22, 2026

Codecov Report

❌ Patch coverage is 96.77419% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 80.26%. Comparing base (cc42fb5) to head (6958374).
⚠️ Report is 5 commits behind head on main.

Files with missing lines Patch % Lines
...nfrastructure/Mistral/VibeSessionLogAnalyzer.swift 96.00% 3 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #161      +/-   ##
==========================================
+ Coverage   80.06%   80.26%   +0.19%     
==========================================
  Files         102      104       +2     
  Lines        7741     7834      +93     
==========================================
+ Hits         6198     6288      +90     
- Misses       1543     1546       +3     
Files with missing lines Coverage Δ
...ces/Infrastructure/Mistral/MistralUsageProbe.swift 100.00% <100.00%> (ø)
...nfrastructure/Mistral/VibeSessionLogAnalyzer.swift 96.00% <96.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@hanrw hanrw merged commit c62a523 into tddworks:main Mar 22, 2026
5 checks passed
@hanrw
Copy link
Copy Markdown
Member

hanrw commented Mar 22, 2026

@farmdawgnation great job! thanks!

@farmdawgnation farmdawgnation deleted the msf/mistral-support-3wx branch March 22, 2026 12:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants