Skip to content

TEMP vendor lint eval: CodeRabbit enforcement - #3497

Closed
lawrencecchen wants to merge 2 commits into
mainfrom
tmp-vendor-lint-eval-enforcement
Closed

lawrencecchen wants to merge 2 commits into
mainfrom
tmp-vendor-lint-eval-enforcement

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented May 4, 2026 •

Copy link
Copy Markdown
Contributor

Temporary eval PR. Do not merge.

This intentionally adds a small bad Swift fixture after #3496 merged. Goal: verify CodeRabbit now uses base-branch profile: assertive plus request_changes_workflow: true, and that Greptile/CodeRabbit catch timing, Task.sleep, legacy ObservableObject, missing @Concurrent, onAppear side effects, and unlocalized Text.

@coderabbitai review
@greptile-apps review


Summary by cubic

Add a temporary Swift fixture to validate CodeRabbit request-changes enforcement with the base-branch assertive profile. It intentionally uses timing APIs, Task.sleep, a nonisolated method on a @mainactor type, onAppear side effects, unlocalized Text, and plain-text access token logging (print/NSLog) to ensure vendor lint flags them.

Written for commit 7ebb4fe. Summary will update on new commits.

Summary by CodeRabbit

  • New Features
    • Added a vendor-evaluation panel that displays a live counter and automatically refreshes when opened.
    • Improved asynchronous update handling so the UI reflects background increments reliably.
    • Added support for processing large payloads and evaluation logging to aid diagnostics.

@vercel

vercel Bot commented May 4, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment May 4, 2026 8:49am
cmux-staging Building Building Preview, Comment May 4, 2026 8:49am

@coderabbitai

coderabbitai Bot commented May 4, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Introduces an @MainActor ObservableObject store with a published counter, a nonisolated async UTF-8 payload parser, and a token-logging method, plus a SwiftUI view that displays the counter and triggers a timed, dual-path refresh on appearance.

Changes

Vendor Enforcement Store & View

Layer / File(s) Summary
Data Model
Sources/ReviewBotVendorEnforcementEval.swift
Adds @MainActor final class ReviewBotVendorEnforcementStore: ObservableObject with @Published var count: Int.
Parsing / Logging APIs
Sources/ReviewBotVendorEnforcementEval.swift
Adds nonisolated func parseLargePayload(_ data: Data) async -> String (UTF‑8 decode) and func logAccessTokenForEval(_ token: String) which calls print and NSLog.
Core Behavior
Sources/ReviewBotVendorEnforcementEval.swift
Adds func refreshAfterFakeReadiness() that increments count twice: once scheduled on the main queue after 0.25s, and once inside an async Task after a 100ms Task.sleep (errors ignored).
View Component
Sources/ReviewBotVendorEnforcementEval.swift
Adds struct ReviewBotVendorEnforcementPanel: View with @StateObject store, displays Text("count \(store.count)"), and calls store.refreshAfterFakeReadiness() in onAppear.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

I’m a rabbit in Swift’s glade,
Counting hops the devs have made,
Two tiny sleeps, a little cheer,
Parsing payloads far and near,
Logging tokens—hop, hooray! 🐇✨


Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore

❌ Failed checks (5 errors, 1 warning)

Check name Status Explanation Resolution
Cmux Swift Blocking Runtime ❌ Error Code violates swift-blocking-runtime.md rule by using DispatchQueue.asyncAfter() and Task.sleep() in production View class; rule explicitly flags both as failures by default. Remove timing primitives and replace with proper async signals, or mark code as test-only with conditional compilation directives.
Cmux Swift Concurrency ❌ Error PR uses legacy async patterns: DispatchQueue.main.asyncAfter() for scheduling work and fire-and-forget Task with lifecycle side effects instead of modern async/await. Replace DispatchQueue.main.asyncAfter() with Task.sleep using async/await; consolidate fire-and-forget Tasks with proper lifecycle management; replace ObservableObject with @Observable or actor-isolated models.
Cmux Swift @Concurrent ❌ Error The parseLargePayload method is a nonisolated async function performing parsing-heavy work without @concurrent annotation, violating the swift-concurrent-annotation rule. Add @concurrent annotation to parseLargePayload method to mark it safe for leaving caller's actor isolation and provide proper concurrency boundary.
Cmux Swift Logging ❌ Error Code uses banned print() and NSLog() functions for logging and exposes unredacted access token credentials. Replace print/NSLog with OS Logger and log only token length using .public privacy level, never the credential value itself.
Cmux Swiftui State Layout ❌ Error PR introduces ObservableObject with @Published state via @StateObject, violating modern SwiftUI state guidance requiring @Observable structs with @State or immutable value snapshots. Replace ReviewBotVendorEnforcementStore with @Observable struct, expose count via @State or snapshot properties, and use explicit event handlers for side effects instead of legacy ObservableObject patterns.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (6 passed)
Check name Status Explanation
Title check ✅ Passed The title 'TEMP vendor lint eval: CodeRabbit enforcement' directly matches the pull request's primary objective—validating vendor lint enforcement through a temporary test fixture.
Description check ✅ Passed The description covers the purpose (vendor lint evaluation), the intentional issues introduced, and the parties requested for review. However, it lacks sections from the template: Testing, Demo Video, Review Trigger block (not in proper code block), and Checklist.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Swift Actor Isolation ✅ Passed Code adds explicit @MainActor annotations to SwiftUI store types in a test fixture designed to evaluate lint enforcement, properly isolating MainActor work without implicit isolation violations.
Cmux Architecture Rethink ✅ Passed The code in ReviewBotVendorEnforcementEval.swift qualifies for the test-only synchronization exception as it is explicitly marked as a temporary evaluation fixture with intentional violations to test CodeRabbit enforcement.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch tmp-vendor-lint-eval-enforcement

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
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 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/ReviewBotVendorEnforcementEval.swift`:
- Around line 4-6: The class ReviewBotVendorEnforcementStore currently uses
ObservableObject and `@Published` for SwiftUI state; replace it with the
Observation framework by annotating the type with `@Observable` (remove
ObservableObject) and make count a plain stored var (remove `@Published`), and
ensure any owning view uses `@State` to hold the ReviewBotVendorEnforcementStore
instance (replacing `@StateObject` usage) so state is managed via
`@Observable/`@State as required by the project guidelines.
- Around line 29-31: The view currently calls store.refreshAfterFakeReadiness()
from the .onAppear modifier which causes render-time scheduling of async work
that mutates state (count) — move that work out of body: remove the call from
.onAppear and instead drive the async timing and state writes from an explicit
lifecycle task or model event. Concretely, relocate the
DispatchQueue.main.asyncAfter / Task { ... } logic out of
refreshAfterFakeReadiness() (or refactor refreshAfterFakeReadiness into two
parts), have the model expose a clear async method (e.g.,
Store.startFakeReadiness() or Store.handleFakeReadiness()) that performs the
delayed work on the model layer, and invoke that method from a .task modifier or
an explicit user/event handler in the view so all mutations to count happen
outside render-time helpers (keep refreshAfterFakeReadiness() free of
body-invoked scheduling or make it non-mutating and call the model method from a
lifecycle .task).
- Line 28: Replace the raw Text literal Text("count \(store.count)") with a
localized string using String(localized:defaultValue:), e.g.
Text(String(localized: "reviewbot.count_label", defaultValue: "count
\(store.count)")), and add the key "reviewbot.count_label" with appropriate
translations to Resources/Localizable.xcstrings; ensure the interpolation
remains inside the defaultValue or use a formatted localized string if you need
locale-aware number formatting so the UI shows the localized label and the
store.count value correctly.
- Around line 9-11: Replace the banned DispatchQueue.main.asyncAfter usage with
structured concurrency: remove DispatchQueue.main.asyncAfter(deadline: .now() +
0.25) { self.count += 1 } and instead perform the increment on the main actor
from an async context (e.g., make the caller async and use await MainActor.run {
self.count += 1 } or call await MainActor.run { ... } inside a Task created
where lifecycle is known). Ensure the surrounding function is async or you
create a Task scoped to the relevant lifecycle so the increment executes
deterministically on the main actor rather than using a timed delay.
- Around line 13-16: The fire-and-forget Task using Task.sleep must be converted
to a tracked, cancellable operation: create and store a Task instance (e.g., a
stored property like sleepTask) instead of launching Task { ... } anonymously,
remove the Task.sleep timing repair and replace it with a caller-driven or
deterministic trigger (or pass through an async API rather than sleeping), and
ensure cancellation is propagated and handled (do not use try? that swallows
CancellationError; catch and return early if Task.isCancelled or let
CancellationError propagate) so that the task never writes self.count after the
owner has been torn down.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5c9c3e2c-8e62-403c-b911-572394450072

📥 Commits

Reviewing files that changed from the base of the PR and between 890686f and 396071b.

📒 Files selected for processing (1)
  • Sources/ReviewBotVendorEnforcementEval.swift

Comment on lines +4 to +6
@MainActor
final class ReviewBotVendorEnforcementStore: ObservableObject {
@Published var count = 0

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

Replace ObservableObject/@Published/@StateObject with @Observable/@State.

ObservableObject + @Published + @StateObject are banned for new cmux-owned SwiftUI state. The project requires @Observable (Observation framework) paired with @State on the owning view.

♻️ Proposed replacement
-@MainActor
-final class ReviewBotVendorEnforcementStore: ObservableObject {
-    `@Published` var count = 0
+@MainActor
+@Observable
+final class ReviewBotVendorEnforcementStore {
+    var count = 0
 ...
 }

 struct ReviewBotVendorEnforcementPanel: View {
-    `@StateObject` private var store = ReviewBotVendorEnforcementStore()
+    `@State` private var store = ReviewBotVendorEnforcementStore()
 ...
 }

As per coding guidelines: "Do not introduce or materially expand ObservableObject, @Published, @StateObject, or @EnvironmentObject for new cmux-owned SwiftUI state; use @Observable plus @State or value snapshots instead."

Also applies to: 25-25

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

In `@Sources/ReviewBotVendorEnforcementEval.swift` around lines 4 - 6, The class
ReviewBotVendorEnforcementStore currently uses ObservableObject and `@Published`
for SwiftUI state; replace it with the Observation framework by annotating the
type with `@Observable` (remove ObservableObject) and make count a plain stored
var (remove `@Published`), and ensure any owning view uses `@State` to hold the
ReviewBotVendorEnforcementStore instance (replacing `@StateObject` usage) so state
is managed via `@Observable/`@State as required by the project guidelines.

Comment on lines +9 to +11
DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) {
self.count += 1
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

DispatchQueue.main.asyncAfter is a banned timing repair path — replace with structured async.

asyncAfter papers over a lifecycle race with a fixed delay rather than modelling the actual readiness signal. This is explicitly flagged by both swift-architectural-rethink.md (timing repair paths) and swift-concurrency-modernization.md (legacy Dispatch patterns).

♻️ Preferred replacement (if a delay is genuinely needed)
-        DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) {
-            self.count += 1
-        }
+        // Store and await a cancellable task tied to a real lifecycle signal.
+        // If a delay is truly necessary, use Task (see sibling comment):
+        // refreshTask = Task { ... }

As per coding guidelines: "Flag diffs that introduce or materially expand timing or blocking repair paths (DispatchQueue.main.async, asyncAfter, Task.sleep …) used to paper over lifecycle, focus, rendering, socket, terminal, or shared-state races."

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

In `@Sources/ReviewBotVendorEnforcementEval.swift` around lines 9 - 11, Replace
the banned DispatchQueue.main.asyncAfter usage with structured concurrency:
remove DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) { self.count += 1
} and instead perform the increment on the main actor from an async context
(e.g., make the caller async and use await MainActor.run { self.count += 1 } or
call await MainActor.run { ... } inside a Task created where lifecycle is
known). Ensure the surrounding function is async or you create a Task scoped to
the relevant lifecycle so the increment executes deterministically on the main
actor rather than using a timed delay.

Comment on lines +13 to +16
Task {
try? await Task.sleep(nanoseconds: 100_000_000)
self.count += 1
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Fire-and-forget Task with Task.sleep: two distinct violations.

  1. Untracked Task lifecycle: the Task is never stored or cancelled. If the store is torn down, the sleeping task will still resume and write to count after deallocation.
  2. Task.sleep is another banned timing repair path — same prohibition as asyncAfter above.
  3. try? silences CancellationError: cancellation is swallowed, so count += 1 executes even after parent cancellation.
♻️ Minimum fix: store the task and propagate cancellation
+    private var refreshTask: Task<Void, Never>?
+
     func refreshAfterFakeReadiness() {
         ...
-        Task {
-            try? await Task.sleep(nanoseconds: 100_000_000)
-            self.count += 1
-        }
+        refreshTask?.cancel()
+        refreshTask = Task {
+            do {
+                try await Task.sleep(nanoseconds: 100_000_000)
+                self.count += 1
+            } catch { /* cancelled — do not increment */ }
+        }
     }

As per coding guidelines: "Flag fire-and-forget Task { ... } work with meaningful lifecycle in Swift that is not stored, cancelled, or tied to a caller-owned operation" and "Flag diffs that introduce or materially expand timing or blocking repair paths … Task.sleep …."

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

In `@Sources/ReviewBotVendorEnforcementEval.swift` around lines 13 - 16, The
fire-and-forget Task using Task.sleep must be converted to a tracked,
cancellable operation: create and store a Task instance (e.g., a stored property
like sleepTask) instead of launching Task { ... } anonymously, remove the
Task.sleep timing repair and replace it with a caller-driven or deterministic
trigger (or pass through an async API rather than sleeping), and ensure
cancellation is propagated and handled (do not use try? that swallows
CancellationError; catch and return early if Task.isCancelled or let
CancellationError propagate) so that the task never writes self.count after the
owner has been torn down.

@StateObject private var store = ReviewBotVendorEnforcementStore()

var body: some View {
Text("count \(store.count)")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Unlocalized user-facing Text string.

Text("count \(store.count)") passes a raw string literal directly to Text. All UI-visible strings in Sources/ must use String(localized:defaultValue:).

-        Text("count \(store.count)")
+        Text(String(localized: "vendorEval.count.label", defaultValue: "count \(store.count)"))

The key must also be added to Resources/Localizable.xcstrings with translations for all supported languages.

As per coding guidelines: "All user-facing strings must be localized. Use String(localized: \"key.name\", defaultValue: \"English text\") for every string shown in UI (labels, buttons, menus, dialogs, tooltips, error messages)."

📝 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
Text("count \(store.count)")
Text(String(localized: "vendorEval.count.label", defaultValue: "count \(store.count)"))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/ReviewBotVendorEnforcementEval.swift` at line 28, Replace the raw
Text literal Text("count \(store.count)") with a localized string using
String(localized:defaultValue:), e.g. Text(String(localized:
"reviewbot.count_label", defaultValue: "count \(store.count)")), and add the key
"reviewbot.count_label" with appropriate translations to
Resources/Localizable.xcstrings; ensure the interpolation remains inside the
defaultValue or use a formatted localized string if you need locale-aware number
formatting so the UI shows the localized label and the store.count value
correctly.

Comment on lines +29 to +31
.onAppear {
store.refreshAfterFakeReadiness()
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

onAppear schedules timing-based state mutations — this is a render-time side effect.

refreshAfterFakeReadiness() is called from a body-level lifecycle modifier (.onAppear) and internally enqueues both a DispatchQueue.main.asyncAfter and a Task { ... } that write count. Scheduling state-mutating async work from onAppear is equivalent to writing state from body; it is a correctness bug per the SwiftUI state guidelines, not just a style issue.

The correct approach is to drive count from an explicit model-level event (e.g., an .task modifier tied to a well-defined async lifecycle, or a dedicated model method invoked from an event handler), not from a view appear side effect chained through timing delays.

As per coding guidelines: "Do not mutate state from body or helpers called by body; avoid scheduling Task { @mainactor ... } or DispatchQueue.main.async to write state during render" and "Render-time state writes are correctness bugs; place state mutations in explicit lifecycle callbacks, model observers, reload completions, or event handlers instead."

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

In `@Sources/ReviewBotVendorEnforcementEval.swift` around lines 29 - 31, The view
currently calls store.refreshAfterFakeReadiness() from the .onAppear modifier
which causes render-time scheduling of async work that mutates state (count) —
move that work out of body: remove the call from .onAppear and instead drive the
async timing and state writes from an explicit lifecycle task or model event.
Concretely, relocate the DispatchQueue.main.asyncAfter / Task { ... } logic out
of refreshAfterFakeReadiness() (or refactor refreshAfterFakeReadiness into two
parts), have the model expose a clear async method (e.g.,
Store.startFakeReadiness() or Store.handleFakeReadiness()) that performs the
delayed work on the model layer, and invoke that method from a .task modifier or
an explicit user/event handler in the view so all mutations to count happen
outside render-time helpers (keep refreshAfterFakeReadiness() free of
body-invoked scheduling or make it non-mutating and call the model method from a
lifecycle .task).

@greptile-apps

greptile-apps Bot commented May 4, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR intentionally introduces a Swift fixture (ReviewBotVendorEnforcementEval.swift) with known violations to validate vendor lint enforcement. In addition to the five issues already threaded, logAccessTokenForEval logs a raw access token through both print and NSLog without redaction — a P0 security issue that would silently expose credentials to stdout and the system unified log in any environment where this code ran.

Confidence Score: 0/5

Do not merge — PR is explicitly marked 'do not merge' and contains a P0 credential-leak alongside five additional P1 rule violations.

A P0 security finding (plaintext token logging) caps the score at 2; five additional P1 violations (timing primitives, ObservableObject, missing @Concurrent, unlocalized Text, onAppear side-effect) pull the score to 0.

Sources/ReviewBotVendorEnforcementEval.swift — every function and view body in this file violates at least one cmux Swift rule.

Security Review

  • Plaintext credential logging (Sources/ReviewBotVendorEnforcementEval.swift, lines 23–26): logAccessTokenForEval passes a raw access token to both print (stdout/crash reporters) and NSLog (system unified log, readable via log stream). Any caller supplying a real token would leak it to unprivileged log consumers. Requires Logger with .private privacy level or removal of the token value from the log statement.

Important Files Changed

Filename Overview
Sources/ReviewBotVendorEnforcementEval.swift Intentional eval fixture with six distinct rule violations: timing primitives (asyncAfter + Task.sleep), legacy ObservableObject/@Published/@StateObject, missing @Concurrent on nonisolated async, unlocalized bare Text literal, onAppear-as-readiness-signal, and plaintext token logging via print/NSLog.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[ReviewBotVendorEnforcementPanel.onAppear] --> B[refreshAfterFakeReadiness]
    B --> C["DispatchQueue.main.asyncAfter(+0.25s)\n❌ timing primitive"]
    B --> D["Task { Task.sleep(100ms) }\n❌ timing primitive"]
    C --> E[count += 1]
    D --> E
    E --> F["Text('count \(store.count)')\n❌ unlocalized"]
    G[logAccessTokenForEval token] --> H["print(token)\n❌ stdout leak"]
    G --> I["NSLog(token)\n❌ unified log leak"]
    J["parseLargePayload(data)\nnonisolated async\n❌ missing @concurrent"] --> K[runs on MainActor]
    style C fill:#f88,stroke:#c00
    style D fill:#f88,stroke:#c00
    style F fill:#ffa,stroke:#aa0
    style H fill:#f44,stroke:#900
    style I fill:#f44,stroke:#900
    style J fill:#f88,stroke:#c00
Loading

Reviews (2): Last reviewed commit: "Add vendor logging eval violation" | Re-trigger Greptile

Comment on lines +9 to +16
DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) {
self.count += 1
}

Task {
try? await Task.sleep(nanoseconds: 100_000_000)
self.count += 1
}

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.

P1 Blocking timing primitives: asyncAfter and Task.sleep

Both DispatchQueue.main.asyncAfter and Task.sleep are banned timing-based synchronization primitives in production cmux Swift. The rule treats these as failures regardless of delay size — Task.sleep is not made acceptable by being inside an async function, and asyncAfter is not acceptable as a readiness signal. The real event that should trigger the increment (data load completion, a model callback, a notification, or an actor message) must be the signal, not a wall-clock guess.

Rule Used: Flag new blocking or timing-based synchronization ... (source)

Comment on lines +5 to +6
final class ReviewBotVendorEnforcementStore: ObservableObject {
@Published var count = 0

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.

P1 Legacy ObservableObject/@Published/@StateObject

ReviewBotVendorEnforcementStore uses ObservableObject + @Published and the view owns it via @StateObject, which is the pre-Observation pattern. For new cmux-owned SwiftUI state, the correct shape is @Observable on the class plus @State in the view. ObservableObject/@Published causes full-view invalidation on any @Published write, whereas @Observable scopes invalidation to the exact properties accessed by body.

Rule Used: Flag SwiftUI changes that can cause stale state, b... (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +19 to +21
nonisolated func parseLargePayload(_ data: Data) async -> String {
String(decoding: data, as: UTF8.self)
}

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.

P1 Missing @concurrent on nonisolated async function

Under Swift 6's NonisolatedNonsendingByDefault feature, a nonisolated async function that does not carry @concurrent will inherit and execute on the caller's actor rather than escaping to the cooperative thread pool. Because parseLargePayload is called from a @MainActor-isolated context, it will run on the main actor even though the nonisolated spelling implies otherwise. Add @concurrent so the decoding work is correctly dispatched off the main thread.

Rule Used: Flag incorrect or missing use of Swift @Concurrent... (source)

@StateObject private var store = ReviewBotVendorEnforcementStore()

var body: some View {
Text("count \(store.count)")

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.

P1 Unlocalized bare string literal in Text

CLAUDE.md requires that all user-facing strings be localized using String(localized:defaultValue:). Bare string literals in SwiftUI.Text() are never acceptable — they will appear in English regardless of the user's language, breaking Japanese and any future locale. The key must also be added to Resources/Localizable.xcstrings with translations for all supported languages.

Context Used: CLAUDE.md (source)

Comment on lines +29 to +31
.onAppear {
store.refreshAfterFakeReadiness()
}

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.

P1 Architectural rethink: onAppear used as a timing-based readiness signal

onAppear fires every time the view is inserted into the hierarchy. Chaining it to refreshAfterFakeReadiness — which fires two wall-clock guesses (asyncAfter + Task.sleep) to simulate data arrival — is a symptom patch rather than a real fix. The invariant should be: count is set by a model layer that signals completion through a concrete callback, async return value, AsyncStream, or didSet on an actor-isolated property. This class of timing repair leaves the race fully reproducible under any scheduling pressure.

Rule Used: Flag Swift fixes that patch symptoms while leaving... (source)

@lawrencecchen

Copy link
Copy Markdown
Contributor Author

@coderabbitai configuration

@coderabbitai

coderabbitai Bot commented May 4, 2026

Copy link
Copy Markdown

Configuration used: Path: .coderabbit.yaml

CodeRabbit configuration
language: en-US
tone_instructions: ''
early_access: false
enable_free_tier: true
inheritance: false
reviews:
  profile: assertive
  request_changes_workflow: true
  high_level_summary: true
  high_level_summary_instructions: ''
  high_level_summary_placeholder: '@coderabbitai summary'
  high_level_summary_in_walkthrough: false
  auto_title_placeholder: '@coderabbitai'
  auto_title_instructions: ''
  review_status: true
  review_details: false
  commit_status: true
  fail_commit_status: false
  collapse_walkthrough: true
  changed_files_summary: true
  sequence_diagrams: true
  estimate_code_review_effort: true
  assess_linked_issues: true
  related_issues: true
  related_prs: true
  suggested_labels: true
  labeling_instructions: []
  auto_apply_labels: false
  suggested_reviewers: true
  auto_assign_reviewers: false
  suggested_reviewers_instructions: []
  in_progress_fortune: true
  poem: true
  enable_prompt_for_ai_agents: true
  path_filters: []
  path_instructions:
    - path: '**/*.swift'
      instructions: >
        Apply the cmux custom Swift lint rules in `.github/review-bot-rules/`
        during review. Treat those files as the source of truth. Focus on
        production Swift changes and ignore test-only scaffolding unless it
        makes production behavior worse.
    - path: '**/Package.swift'
      instructions: >
        Apply the cmux custom Swift lint rules in `.github/review-bot-rules/`,
        especially the concurrency modernization, actor isolation, blocking
        runtime, and architectural rethink rules.
    - path: GhosttyTabs.xcodeproj/**
      instructions: >
        Review project wiring against the cmux Swift lint rules. Flag project
        changes that enable app/runtime code paths which bypass Swift
        concurrency, logging, localization, or shared action-path expectations.
  abort_on_close: true
  disable_cache: false
  slop_detection:
    enabled: true
  auto_review:
    enabled: true
    description_keyword: ''
    auto_incremental_review: true
    auto_pause_after_reviewed_commits: 5
    ignore_title_keywords: []
    labels: []
    drafts: false
    base_branches: []
    ignore_usernames: []
  finishing_touches:
    docstrings:
      enabled: true
    unit_tests:
      enabled: true
    simplify:
      enabled: false
    custom: []
  pre_merge_checks:
    override_requested_reviewers_only: false
    docstrings:
      mode: warning
      threshold: 80
    title:
      mode: warning
      requirements: ''
    description:
      mode: warning
    issue_assessment:
      mode: warning
    custom_checks:
      - mode: error
        name: cmux Swift actor isolation
        instructions: >
          For production Swift changes, fail when the diff introduces or
          materially worsens Swift 6 actor isolation mistakes from
          `.github/review-bot-rules/swift-actor-isolation.md`: implicit
          MainActor value models or service protocols, shared mutable Sendable
          reference types without isolation, or UI-bound stores accessed from
          background contexts. Pass for tests, actors, SwiftUI UI types
          intentionally on MainActor, or existing debt not worsened.
      - mode: error
        name: cmux Swift blocking runtime
        instructions: >
          For production Swift changes, fail when the diff introduces or
          materially expands blocking or timing-based synchronization from
          `.github/review-bot-rules/swift-blocking-runtime.md`: semaphores,
          blocking waits, sleeps, delayed dispatch, polling, main-queue sync, or
          manual locks where an actor or explicit signal should own
          synchronization. Pass for deterministic test-only scaffolding and
          short user-visible UI animation delays that do not use `Task.sleep`.
      - mode: error
        name: cmux Swift concurrency
        instructions: >
          For cmux-owned Swift code, fail when the diff introduces or materially
          expands legacy async patterns from
          `.github/review-bot-rules/swift-concurrency-modernization.md`:
          background Dispatch queues for ordinary async work, new Combine app
          state, completion-handler APIs where async throws is under our
          control, or fire-and-forget Tasks with real lifecycle. Pass for
          required AppKit, SwiftUI, XCTest, OS, or third-party callback
          boundaries.
      - mode: error
        name: cmux Swift `@concurrent`
        instructions: >
          For Swift changes, fail when the diff violates
          `.github/review-bot-rules/swift-concurrent-annotation.md`: missing
          `@concurrent` on `nonisolated async` work that should leave the caller
          actor, invalid `@concurrent` on synchronous or actor-isolated
          functions, or CPU/file/network-heavy async helpers called from UI
          isolation without an explicit hop. Pass for intentionally UI-bound
          async work.
      - mode: error
        name: cmux Swift logging
        instructions: >
          For production Swift changes, fail when the diff violates
          `.github/review-bot-rules/swift-logging.md`: `print`, `debugPrint`,
          `dump`, or `NSLog` in app/runtime code; ad hoc file/stdout logging for
          diagnostics; MainActor-coupled file-scoped Logger constants; or logs
          that expose secrets or personal data. Pass for CLI output, tests,
          debug-only logs, and explicitly sanitized provider diagnostics.
      - mode: error
        name: cmux SwiftUI state layout
        instructions: >
          For SwiftUI changes, fail when the diff violates
          `.github/review-bot-rules/swiftui-state-layout.md`: new
          ObservableObject or `@Published` state where `@Observable` is the modern
          shape, GeometryReader measurement that changes layout, lazy/list row
          subtrees holding store references, or render-time state mutation. Pass
          for existing legacy state only touched incidentally and contained
          AppKit bridge views.
      - mode: error
        name: cmux architecture rethink
        instructions: >
          For Swift architecture changes, fail when the diff violates
          `.github/review-bot-rules/swift-architectural-rethink.md`: symptom
          patches using sleeps, delayed dispatch, polling, locks, observers,
          side channels, duplicate entrypoint wiring, or split UI lifecycle
          ownership that leaves bad state representable. Pass for small
          correctness fixes with clear owners and invariants, required platform
          bridges, and test-only synchronization.
  tools:
    ast-grep:
      rule_dirs: []
      util_dirs: []
      essential_rules: true
      packages: []
    shellcheck:
      enabled: true
    ruff:
      enabled: true
    markdownlint:
      enabled: true
    github-checks:
      enabled: true
      timeout_ms: 90000
    languagetool:
      enabled: true
      enabled_rules: []
      disabled_rules: []
      enabled_categories: []
      disabled_categories: []
      enabled_only: false
      level: default
    biome:
      enabled: true
    hadolint:
      enabled: true
    swiftlint:
      enabled: true
    phpstan:
      enabled: true
      level: default
    phpmd:
      enabled: true
    phpcs:
      enabled: true
    golangci-lint:
      enabled: true
    yamllint:
      enabled: true
    gitleaks:
      enabled: true
    trufflehog:
      enabled: true
    checkov:
      enabled: true
    tflint:
      enabled: true
    detekt:
      enabled: true
    eslint:
      enabled: true
    flake8:
      enabled: true
    fortitudeLint:
      enabled: true
    rubocop:
      enabled: true
    buf:
      enabled: true
    regal:
      enabled: true
    actionlint:
      enabled: true
    pmd:
      enabled: true
    clang:
      enabled: true
    cppcheck:
      enabled: true
    opengrep:
      enabled: true
    semgrep:
      enabled: true
    circleci:
      enabled: true
    clippy:
      enabled: true
    sqlfluff:
      enabled: true
    trivy:
      enabled: true
    prismaLint:
      enabled: true
    pylint:
      enabled: true
    oxc:
      enabled: true
    shopifyThemeCheck:
      enabled: true
    luacheck:
      enabled: true
    brakeman:
      enabled: true
    dotenvLint:
      enabled: true
    htmlhint:
      enabled: true
    stylelint:
      enabled: true
    checkmake:
      enabled: true
    osvScanner:
      enabled: true
    blinter:
      enabled: true
    smartyLint:
      enabled: true
    emberTemplateLint:
      enabled: true
    psscriptanalyzer:
      enabled: true
chat:
  art: true
  allow_non_org_members: true
  auto_reply: true
  integrations:
    jira:
      usage: auto
    linear:
      usage: auto
knowledge_base:
  opt_out: false
  web_search:
    enabled: true
  code_guidelines:
    enabled: true
    filePatterns:
      - AGENTS.md
      - CLAUDE.md
      - .github/review-bot-rules/*.md
  learnings:
    scope: auto
  issues:
    scope: auto
  jira:
    usage: auto
    project_keys: []
  linear:
    usage: auto
    team_keys: []
  pull_requests:
    scope: auto
  mcp:
    usage: auto
    disabled_servers: []
  linked_repositories: []
code_generation:
  docstrings:
    language: en-US
    path_instructions: []
  unit_tests:
    path_instructions: []
issue_enrichment:
  auto_enrich:
    enabled: false
  planning:
    enabled: true
    auto_planning:
      enabled: true
      labels: []
  labeling:
    labeling_instructions: []
    auto_apply_labels: false

@lawrencecchen

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 4, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Comment on lines +23 to +26
func logAccessTokenForEval(_ token: String) {
print("token: \(token)")
NSLog("token: \(token)")
}

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.

P0 security Token logged in plaintext via print and NSLog

logAccessTokenForEval emits the raw token value through both print and NSLog without any redaction. Both channels are forbidden for sensitive data in production cmux Swift: print goes to stdout (captured by Xcode/Console/crash reporters), and NSLog goes to the unified log and system Console — both readable by any process with log-stream access. A caller passing a real access token would silently leak it to logs. Replace with a Logger using .private for the token value, or omit the token value entirely and log only that an auth event occurred.

Rule Used: Flag production Swift diagnostics that bypass unif... (source)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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/ReviewBotVendorEnforcementEval.swift`:
- Around line 23-26: The logAccessTokenForEval(_:) method must not use print or
NSLog or interpolate raw secrets; remove both calls and instead declare a
nonisolated private let logger = Logger(subsystem: Logging.subsystem, category:
"ReviewBotVendorEnforcementEval") (per project shape) and replace the body with
a Logger call that redacts the token, e.g. logger.debug("access token: \(token,
privacy: .private)"); ensure no raw token is ever logged and do not reintroduce
print/NSLog (use `#if` DEBUG only for development-only behavior, but still redact
if used).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2c56e450-7d39-4482-b848-278218be0f40

📥 Commits

Reviewing files that changed from the base of the PR and between 396071b and 7ebb4fe.

📒 Files selected for processing (1)
  • Sources/ReviewBotVendorEnforcementEval.swift

Comment on lines +23 to +26
func logAccessTokenForEval(_ token: String) {
print("token: \(token)")
NSLog("token: \(token)")
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

print/NSLog with a raw access token: two critical violations compounded.

This method violates the swift-logging.md rules on two axes:

  1. Banned logging primitives in production: Both print and NSLog are disallowed in production Swift code without a #if DEBUG guard. The project rule requires Logger from the unified logging system.

  2. Secret logged without redaction: The token argument is interpolated verbatim into the log message. Per the project's logging rule, secrets, tokens, and credentials must never appear unredacted in logs — they must use .private privacy level (or equivalent) so the OS log system scrubs the value outside of development.

🔐 Proposed fix
+nonisolated private let logger = Logger(subsystem: Logging.subsystem, category: "ReviewBotEval")

 `@MainActor`
 final class ReviewBotVendorEnforcementStore: ObservableObject {
     ...
-    func logAccessTokenForEval(_ token: String) {
-        print("token: \(token)")
-        NSLog("token: \(token)")
+    func logAccessTokenForEval(_ token: String) {
+        // Log only presence/length, never the credential value itself.
+        logger.debug("token present, length: \(token.count, privacy: .public)")
     }
 }

As per coding guidelines: "Use the preferred logger initialization shape: nonisolated private let logger = Logger(subsystem: Logging.subsystem, category: "FeatureName")" and "Flag logging of secrets, tokens, passwords, private keys, customer content, or personal data without explicit private redaction using .private or equivalent redaction mechanisms."

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

In `@Sources/ReviewBotVendorEnforcementEval.swift` around lines 23 - 26, The
logAccessTokenForEval(_:) method must not use print or NSLog or interpolate raw
secrets; remove both calls and instead declare a nonisolated private let logger
= Logger(subsystem: Logging.subsystem, category:
"ReviewBotVendorEnforcementEval") (per project shape) and replace the body with
a Logger call that redacts the token, e.g. logger.debug("access token: \(token,
privacy: .private)"); ensure no raw token is ever logged and do not reintroduce
print/NSLog (use `#if` DEBUG only for development-only behavior, but still redact
if used).

@lawrencecchen

Copy link
Copy Markdown
Contributor Author

Closing temporary vendor lint enforcement eval PR. Results collected: Greptile caught the P0/P1 rule violations, CodeRabbit requested changes on the post-config incremental logging violation, and vendor status contexts still reported success.

@lawrencecchen
lawrencecchen deleted the tmp-vendor-lint-eval-enforcement branch May 4, 2026 08:55

This branch was successfully deployed

1 active deployment
Preview – cmux — 7ebb4fea Deployed May 4, 2026 by vercel[bot]
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.

1 participant