Skip to content

chore: enforce no-floating-promises in core/task/#253

Open
0xMink wants to merge 1 commit into
chore/no-floating-promises-activatefrom
chore/no-floating-promises-core-task
Open

chore: enforce no-floating-promises in core/task/#253
0xMink wants to merge 1 commit into
chore/no-floating-promises-activatefrom
chore/no-floating-promises-core-task

Conversation

@0xMink
Copy link
Copy Markdown
Contributor

@0xMink 0xMink commented May 22, 2026

Summary

Next slice of the no-floating-promises ratchet (follows #251). Widens the rule's scope in eslint.config.mjs to include core/task/**.

Stacked on #251 — this PR's base is chore/no-floating-promises-activate so the diff shows only the core/task/ changes. Merge #251 first.

core/task/ had 25 un-awaited promises.

Task.ts — 19, all marked void

Every one is genuine fire-and-forget, so void (which preserves current behavior) is the correct fix:

  • presentAssistantMessage(this) — its doc comment describes a self-locking streaming presenter designed to be called concurrently/fire-and-forget; awaiting it would be wrong.
  • 3× task-loop kickoffstartTask/resumeTaskFromHistory in the constructor and the synchronous start(); awaiting isn't possible there and the task is meant to run in the background.
  • updateClineMessage — UI message posts in the hot streaming path. await would change streaming behavior; void preserves it, and the file already uses void this.updateClineMessage(...) at line 1396.
  • 2× other UI posts — in a synchronous handler and a setTimeout callback.
  • getCheckpointService(this) — the existing comment states it kicks the work off "in the background".

Task.spec.ts — 6, awaited

Un-awaited task.submitUserMessage(...) calls in async tests — tests should await the action under test; these are now awaited.

Test plan

  • eslint core/task/ clean.
  • eslint . --ext=ts --max-warnings=0 (the repo lint command) passes.
  • tsc --noEmit clean.
  • core/task/ test suite passes (17 files, 175 tests).

Next slice of the no-floating-promises ratchet — widens the rule's scope in eslint.config.mjs to core/task/**. core/task/ had 25 un-awaited promises. Task.ts (19): all genuine fire-and-forget, marked void — task-loop kickoffs in the constructor and start(), UI posts in synchronous/streaming/setTimeout paths, the explicitly-background checkpoint init, and 9 presentAssistantMessage calls (a self-locking streaming presenter designed for fire-and-forget). void preserves current behavior, and the file already uses void this.updateClineMessage(...) elsewhere. Task.spec.ts (6): un-awaited task.submitUserMessage(...) calls in async tests, now awaited.
Copilot AI review requested due to automatic review settings May 22, 2026 09:16
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 22, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 188a2272-71b1-40a9-a109-f5e5ffcf8943

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/no-floating-promises-core-task

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.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Expands the @typescript-eslint/no-floating-promises “ratchet” to cover src/core/task/**, and updates Task implementation + tests to satisfy the rule without changing intended async behavior.

Changes:

  • Extend eslint.config.mjs to enforce no-floating-promises in core/task/**/*.ts.
  • Mark intended fire-and-forget async calls in Task.ts with void.
  • Await submitUserMessage(...) in async tests to ensure actions under test complete before assertions.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
src/eslint.config.mjs Adds core/task/**/*.ts to the scoped no-floating-promises enforcement block.
src/core/task/Task.ts Replaces floating promises with explicit void for intentional background operations / UI updates.
src/core/task/__tests__/Task.spec.ts Awaits task.submitUserMessage(...) calls in async tests to satisfy lint and improve test determinism.
Comments suppressed due to low confidence (3)

src/core/task/Task.ts:575

  • startTask() / resumeTaskFromHistory() can throw/reject on unexpected failures (they rethrow in their catch blocks). Kicking them off with void in the constructor means those failures become unhandled promise rejections. Consider adding an explicit .catch(...) handler (while keeping the background execution) to log or route errors through provider.log.
		if (startTask) {
			this._started = true
			if (task || images) {
				void this.startTask(task, images)
			} else if (historyItem) {
				void this.resumeTaskFromHistory()
			} else {

src/core/task/Task.ts:1788

  • startTask() is async and may reject; starting it with void here risks an unhandled rejection if initialization fails. Consider handling the background promise with .catch(...) (and optionally logging via the provider) so unexpected failures don’t surface as process-level unhandled rejections.
		const { task, images } = this.metadata

		if (task || images) {
			void this.startTask(task ?? undefined, images ?? undefined)
		}

src/core/task/Task.ts:2772

  • presentAssistantMessage() is async and can reject (e.g., it throws when abort is set). Calling it fire-and-forget via void means a rejection would be unhandled. Consider adding a .catch(...) handler (while keeping it non-blocking) to avoid process-level unhandled rejections during cancellation/aborts.
										// Add to content and present
										this.assistantMessageContent.push(partialToolUse)
										this.userMessageContentReady = false
										void presentAssistantMessage(this)
									} else if (event.type === "tool_call_delta") {

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/core/task/Task.ts
this.emit(RooCodeEventName.TaskUserMessage, this.taskId)
this.emit(RooCodeEventName.QueuedMessagesUpdated, this.taskId, this.messageQueueService.messages)
this.providerRef.deref()?.postStateToWebviewWithoutTaskHistory()
void this.providerRef.deref()?.postStateToWebviewWithoutTaskHistory()
@codecov
Copy link
Copy Markdown

codecov Bot commented May 22, 2026

Codecov Report

❌ Patch coverage is 26.31579% with 14 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/core/task/Task.ts 26.31% 14 Missing ⚠️

📢 Thoughts on this report? Let us know!

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