Skip to content

feat: add daemon foundation#239

Merged
munezaclovis merged 18 commits into
mainfrom
feat/daemon-foundation
May 24, 2026
Merged

feat: add daemon foundation#239
munezaclovis merged 18 commits into
mainfrom
feat/daemon-foundation

Conversation

@munezaclovis

@munezaclovis munezaclovis commented May 24, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add the foreground daemon foundation with versioned Unix-socket NDJSON requests and progress events
  • persist daemon job metadata/final status through the state crate
  • route daemon lifecycle commands, keep daemon:run hidden from help, and document the completions tradeoff

Test Plan

  • cargo nextest run -p pv -p daemon -p state
  • cargo clippy --workspace --all-targets --all-features --locked -- -D warnings
  • cargo shear
  • cargo fmt --all
  • git diff --check

Summary by CodeRabbit

  • New Features

    • Added daemon management commands: enable, disable, restart (plus a hidden run entry)
    • Daemon persists job history and exposes recent jobs (limited to the latest 100)
    • Daemon accepts job requests and streams newline-delimited JSON progress/events; provides restart guidance on protocol version mismatch
  • Documentation

    • Clarified how hidden/internal daemon subcommands appear in shell completions
  • Tests

    • Added integration tests for socket protocol, job streaming, malformed input resilience, stale-socket handling, and recent-jobs behavior

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 24, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a Unix-socket JSON-protocol daemon and RunningDaemon runtime, CLI daemon subcommands (enable/disable/restart/run), state job-tracking APIs and socket helpers, workspace serde deps, and integration tests exercising protocol flows, version mismatch, malformed input, and recent_jobs behavior.

Changes

Daemon Integration

Layer / File(s) Summary
Workspace and crate dependencies
Cargo.toml, DESIGN.md, crates/cli/Cargo.toml, crates/daemon/Cargo.toml
Adds serde/serde_json to workspace deps; CLI crate adds daemon and state path deps; daemon crate lists serde, serde_json, tokio, thiserror and dev-dependencies. Design note clarifies hidden daemon commands may appear in completions.
CLI command arguments and dispatch
crates/cli/src/args.rs, crates/cli/src/commands/mod.rs
Adds daemon subcommands: daemon:enable, daemon:disable, daemon:restart, and hidden daemon:run; execute dispatch routes these to handlers.
CLI daemon handlers and error types
crates/cli/src/commands/daemon.rs, crates/cli/src/error.rs
Implements handlers: enable/disable/restart return a DeferredDaemonLifecycle error; run calls daemon::run_blocking(paths). ExecuteError gains Daemon and State wrapper variants.
CLI execution result handling
crates/cli/src/lib.rs
Introduces finish_execution to centralize mapping ExecuteError variants to exit behavior and stderr output, forwarding Daemon/State errors to outer error conversions.
State: job tracking, paths, and helpers
crates/state/src/database.rs, crates/state/src/lib.rs, crates/state/src/paths.rs, crates/state/src/fs.rs, crates/state/tests/state_foundation.rs
Adds JobRecord, Database job lifecycle APIs (start_job, complete_job, fail_job), recent_jobs bounded query and helpers (ID generation, timestamp), PvPaths::daemon_socket(), remove_daemon_socket(), re-exports JobRecord, and tests seeding 105 jobs to verify the 100-job limit.
Daemon core: protocol, server, jobs, runtime
crates/daemon/src/lib.rs, crates/daemon/src/protocol.rs, crates/daemon/src/error.rs, crates/daemon/src/jobs.rs, crates/daemon/src/server.rs
Implements RunningDaemon with start/shutdown and run_blocking, defines PROTOCOL_VERSION, request/response/event types and write_line, per-connection JSON line protocol handling, run_job event streaming and persistence, and DaemonError.
Daemon integration tests
crates/daemon/tests/daemon_foundation.rs
Integration tests covering run_job happy path, unsupported job handling, protocol-version mismatch, malformed input resilience, idle partial-client behavior, stale-socket cleanup, disconnected job stream scenario, and snapshot helpers.
CLI snapshot tests for daemon commands
it/cli.rs
Snapshot tests verify --help hides the daemon at top level and that daemon:enable/disable/restart are routed as stubbed commands.

Sequence Diagram

sequenceDiagram
  participant CLI as CLI
  participant Daemon as RunningDaemon
  participant Socket as UnixSocket
  participant DB as Database

  CLI->>Daemon: run_blocking(paths)
  Daemon->>Daemon: start() (ensure fs layout, open DB, bind socket)
  Daemon->>Socket: listen

  rect rgba(200, 150, 200, 0.5)
  Socket->>Daemon: accept connection
  CLI->>Socket: send JSON request (protocol_version + command)
  Socket->>Daemon: read request line
  Daemon->>Daemon: validate protocol_version

  alt health
    Daemon->>Socket: write health Ok response
  else run_job
    Daemon->>DB: start_job(kind, scope)
    DB-->>Daemon: JobRecord (job_id)
    Daemon->>Socket: write Accepted response (job_id)
    Daemon->>Socket: write JobStarted event
    Daemon->>Socket: write Progress event
    Daemon->>Socket: write JobCompleted event
    Daemon->>DB: complete_job(job_id, summary)
  end
  end

  CLI->>Daemon: Ctrl-C -> shutdown()
  Daemon->>Daemon: send shutdown signal, await server task, remove socket
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 I nibble logs and watch the queue,

Sockets hum as jobs come through,
Events stream out, then state says done,
Pv sleeps while work gets won,
Hoppity hops — a daemon run!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 31.03% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add daemon foundation' accurately summarizes the main change—adding foundational daemon infrastructure with Unix socket communication and job persistence.
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.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/daemon-foundation

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: 2

🧹 Nitpick comments (1)
crates/state/src/database.rs (1)

115-138: 💤 Low value

Consider adding a LIMIT to recent_jobs for future-proofing.

The method is named recent_jobs but returns all jobs without a limit. As the jobs table grows over time, this could return unbounded results.

For a foundation PR this is acceptable, but consider adding a LIMIT clause (e.g., LIMIT 100) or renaming to all_jobs to clarify intent.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/state/src/database.rs` around lines 115 - 138, The recent_jobs method
returns all rows and should be bounded; modify the SQL in recent_jobs to include
a LIMIT (e.g., change the query to SELECT ... FROM jobs ORDER BY started_at, id
LIMIT 100) so it returns a fixed number of recent JobRecord entries, or
alternatively change recent_jobs signature to accept a configurable limit
parameter and apply that in the prepared statement; update the SQL string and
any call sites accordingly to use the new limit.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/cli/src/lib.rs`:
- Around line 70-85: finish_execution currently treats ExecuteError::Io as a
catch-all and forwards it into an anyhow error path instead of formatting it via
Output::error like ExecuteError::User; update finish_execution to add an
Err(ExecuteError::Io(err)) branch (similar to Err(ExecuteError::User(error)))
that creates Output::new(stderr, output_mode) and calls
output.error(&err.to_string())? and then returns Ok(ExitCode::FAILURE) so IO
errors are formatted via Output::error and exit code remains FAILURE; ensure you
reference ExecuteError::Io, finish_execution, and Output::error when locating
the change.

In `@crates/daemon/src/lib.rs`:
- Around line 129-143: In serve(), don't propagate connection errors from
handle_connection with the `?` — wrap the accept/handle path in a match or if
let and on Err(e) log the error (include context like which client or that
accept/handle failed) and continue the loop so the daemon keeps serving; keep
the shutdown branch unchanged and only return Ok(()) when shutdown fires.
Specifically update the block that calls listener.accept() and
handle_connection(paths.clone(), stream).await so errors are caught (e.g., match
accepted { Ok((stream, addr)) => if let Err(e) = handle_connection(...).await {
error!(%e, "connection handling failed for {addr}") }, Err(e) => error!(%e,
"accept failed") }) and then continue.

---

Nitpick comments:
In `@crates/state/src/database.rs`:
- Around line 115-138: The recent_jobs method returns all rows and should be
bounded; modify the SQL in recent_jobs to include a LIMIT (e.g., change the
query to SELECT ... FROM jobs ORDER BY started_at, id LIMIT 100) so it returns a
fixed number of recent JobRecord entries, or alternatively change recent_jobs
signature to accept a configurable limit parameter and apply that in the
prepared statement; update the SQL string and any call sites accordingly to use
the new limit.
🪄 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 Plus

Run ID: 212313a3-17ca-4c4c-9f55-64bbfb94ecd9

📥 Commits

Reviewing files that changed from the base of the PR and between 6316eb8 and 7862d24.

⛔ Files ignored due to path filters (8)
  • Cargo.lock is excluded by !**/*.lock
  • crates/daemon/tests/snapshots/daemon_foundation__protocol_mismatch_returns_restart_guidance_without_creating_a_job.snap is excluded by !**/*.snap
  • crates/daemon/tests/snapshots/daemon_foundation__socket_protocol_streams_job_progress_and_persists_final_status.snap is excluded by !**/*.snap
  • it/snapshots/cli__completions_generate_bash_script.snap is excluded by !**/*.snap
  • it/snapshots/cli__completions_generate_fish_script.snap is excluded by !**/*.snap
  • it/snapshots/cli__completions_generate_zsh_script.snap is excluded by !**/*.snap
  • it/snapshots/cli__daemon_lifecycle_commands_are_routed_as_stubs.snap is excluded by !**/*.snap
  • it/snapshots/cli__daemon_run_is_hidden_from_top_level_help.snap is excluded by !**/*.snap
📒 Files selected for processing (16)
  • Cargo.toml
  • DESIGN.md
  • crates/cli/Cargo.toml
  • crates/cli/src/args.rs
  • crates/cli/src/commands/daemon.rs
  • crates/cli/src/commands/mod.rs
  • crates/cli/src/error.rs
  • crates/cli/src/lib.rs
  • crates/daemon/Cargo.toml
  • crates/daemon/src/lib.rs
  • crates/daemon/tests/daemon_foundation.rs
  • crates/state/src/database.rs
  • crates/state/src/fs.rs
  • crates/state/src/lib.rs
  • crates/state/src/paths.rs
  • it/cli.rs

Comment thread crates/cli/src/lib.rs
Comment thread crates/daemon/src/lib.rs Outdated

@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 current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/daemon/src/lib.rs`:
- Around line 137-142: The accept() result is being unwrapped with the ?
operator which will terminate the daemon on an accept() error; change the match
arm handling of the select branch so that the AcceptResult is matched and accept
errors are logged/ignored and the loop continues instead of returning—i.e.
replace the let (stream, _address) = accepted?; pattern in the listener.accept()
branch with a match (or if let) that handles Ok((stream, addr)) by calling
handle_connection(paths.clone(), stream).await (as currently done) and handles
Err(e) by logging or ignoring e and continuing the loop so the daemon stays
alive; reference the listener.accept() branch and the handle_connection(...)
call when making this change.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3d94bc96-2c1a-4832-9e32-32239992ceeb

📥 Commits

Reviewing files that changed from the base of the PR and between 7862d24 and 669949d.

⛔ Files ignored due to path filters (2)
  • crates/daemon/tests/snapshots/daemon_foundation__malformed_request_does_not_stop_accepting_connections.snap is excluded by !**/*.snap
  • crates/state/tests/snapshots/state_foundation__recent_jobs_returns_the_latest_one_hundred_jobs.snap is excluded by !**/*.snap
📒 Files selected for processing (5)
  • crates/cli/src/lib.rs
  • crates/daemon/src/lib.rs
  • crates/daemon/tests/daemon_foundation.rs
  • crates/state/src/database.rs
  • crates/state/tests/state_foundation.rs

Comment thread crates/daemon/src/lib.rs Outdated

@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 current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/daemon/src/jobs.rs`:
- Around line 13-55: A started job may be left without a final persisted state
if any write_line call returns early; change the flow so Database::start_job
(and the created job.id) remains, attempt the write_line calls but ensure
database.complete_job(&job.id, summary) is always invoked before returning on
any write error; implement this by performing the write_line calls and capturing
their Result, and on Err call database.complete_job(&job.id, summary)
(propagating the original error afterward), or wrap the write sequence in a
scope that returns its Result but uses a match or finally-like cleanup to call
complete_job on Err, referencing Database::open, Database::start_job,
write_line, &job.id, database.complete_job, and the DaemonEvent writes.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 945cbe38-2b77-4618-8c8e-63a7606618a1

📥 Commits

Reviewing files that changed from the base of the PR and between 669949d and 0fb9fe8.

📒 Files selected for processing (5)
  • crates/daemon/src/error.rs
  • crates/daemon/src/jobs.rs
  • crates/daemon/src/lib.rs
  • crates/daemon/src/protocol.rs
  • crates/daemon/src/server.rs

Comment thread crates/daemon/src/jobs.rs

@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.

🧹 Nitpick comments (1)
crates/daemon/tests/daemon_foundation.rs (1)

107-114: ⚡ Quick win

Assert the health response payload instead of discarding it.

The follow-up health call is a good synchronization point, but ignoring its content makes this test less sensitive to protocol regressions.

Suggested patch
-    let _health = request_lines(
+    let health_lines = request_lines(
         &paths,
         json!({
             "protocol_version": daemon::PROTOCOL_VERSION,
             "command": "health",
         }),
     )
     .await?;
+    assert_eq!(health_lines.len(), 1);
+    assert_eq!(health_lines[0]["type"], json!("response"));
+    assert_eq!(health_lines[0]["status"], json!("ok"));
+    assert_eq!(health_lines[0]["message"], json!("daemon healthy"));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/daemon/tests/daemon_foundation.rs` around lines 107 - 114, Replace the
discarded `_health` result from the request_lines call with a real assertion:
store the result (e.g., let health = request_lines(...).await?;), parse it as
JSON (serde_json::Value) and assert the expected fields are present and correct
— at minimum assert that health["protocol_version"] == daemon::PROTOCOL_VERSION
and that a health/status field exists (for example health["status"] == "ok" if
applicable); update the test around the request_lines call to fail if the health
payload does not match these expectations so the test detects protocol
regressions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@crates/daemon/tests/daemon_foundation.rs`:
- Around line 107-114: Replace the discarded `_health` result from the
request_lines call with a real assertion: store the result (e.g., let health =
request_lines(...).await?;), parse it as JSON (serde_json::Value) and assert the
expected fields are present and correct — at minimum assert that
health["protocol_version"] == daemon::PROTOCOL_VERSION and that a health/status
field exists (for example health["status"] == "ok" if applicable); update the
test around the request_lines call to fail if the health payload does not match
these expectations so the test detects protocol regressions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6f780682-4989-45f7-984c-10a87940f930

📥 Commits

Reviewing files that changed from the base of the PR and between 0fb9fe8 and efcd209.

⛔ Files ignored due to path filters (1)
  • crates/daemon/tests/snapshots/daemon_foundation__disconnected_job_stream_still_persists_final_status.snap is excluded by !**/*.snap
📒 Files selected for processing (2)
  • crates/daemon/src/jobs.rs
  • crates/daemon/tests/daemon_foundation.rs

@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: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/daemon/src/lib.rs (1)

43-48: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guarantee socket cleanup even when the server task exits with join errors.

On Line 43 and Line 97, task.await? short-circuits before cleanup; on Line 107, task_result? can also return before applying socket_result. This can leave a stale daemon socket and break subsequent starts.

Suggested patch
     pub async fn shutdown(self) -> Result<(), DaemonError> {
         let _ = self.shutdown.send(());
-        let task_result = self.task.await?;
-        let socket_result = state::fs::remove_daemon_socket(&self.paths);
-
-        task_result?;
-        socket_result?;
+        let join_result = self.task.await;
+        let socket_result = state::fs::remove_daemon_socket(&self.paths);
+        socket_result?;
+        let task_result = join_result?;
+        task_result?;
 
         Ok(())
     }
@@
         signal_result = &mut shutdown_signal => {
             signal_result?;
             let _ = shutdown.send(());
-            let task_result = task.await?;
             let socket_result = state::fs::remove_daemon_socket(&paths);
-
-            task_result?;
             socket_result?;
+            let task_result = task.await?;
+            task_result?;
 
             Ok(())
         }
         task_result = &mut task => {
             let socket_result = state::fs::remove_daemon_socket(&paths);
-            let task_result = task_result?;
-
             socket_result?;
+            let task_result = task_result?;
             task_result
         }

Also applies to: 97-101, 106-110

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/daemon/src/lib.rs` around lines 43 - 48, The current code uses ? on
self.task.await and on task_result which short-circuits and skips socket
cleanup; change the flow in the functions using self.task.await and
state::fs::remove_daemon_socket so you first capture the task join result
without bubbling it (let task_result = self.task.await), then always call
state::fs::remove_daemon_socket(&self.paths) to get socket_result, and only
after the removal propagate errors (e.g. return task_result?; socket_result? or
prefer a combined/error-prioritizing strategy); update the code paths that
reference task_result and socket_result (the await and the remove_daemon_socket
calls) so socket cleanup runs even when the task join returns Err.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/daemon/src/server.rs`:
- Around line 28-37: The match arm that currently does `Err(_error) => continue`
can busy-loop on persistent accept() failures; modify the error branch around
the `accepted` handling so it logs or captures the error and then awaits a small
backoff (e.g., tokio::time::sleep for a short Duration like 100–500ms) before
retrying instead of a bare continue. Locate the match in server.rs where
`accepted` is matched and adjust the `Err(...)` arm that is adjacent to
`connections.spawn(... handle_connection ...)` to perform the sleep/backoff (and
optionally a debug/error log) before looping.
- Around line 55-59: Add a read timeout around the initial read from the
transport (the call to transport.next().await that yields line) so a client
can't hold the connection open indefinitely; use tokio::time::timeout (or
futures::future::timeout) to await transport.next() with a configurable
duration, handle the timeout by returning an appropriate error or closing the
connection, and only proceed to serde_json::from_str::<DaemonRequest>(&line?)?
when the timeout succeeds; update any surrounding error handling to distinguish
a timed-out read from other I/O errors and document the timeout value where the
transport.next().await call is performed.

In `@crates/daemon/tests/daemon_foundation.rs`:
- Around line 128-130: The test uses a very tight timeout when awaiting
request_lines: change the Duration::from_millis(250) used in the timeout(...)
call (where `lines` is assigned) to a more permissive value (e.g.,
Duration::from_secs(2) or Duration::from_millis(1500)) to reduce CI flakiness;
update the literal in the timeout invocation that wraps the `request_lines(...)`
call so the test allows more time for async completion.

In `@crates/state/src/database.rs`:
- Around line 131-136: complete_job and fail_job treat UPDATE as successful even
if no row was updated; after calling transaction.execute(...) (which returns a
usize), capture the returned count (e.g., let updated =
transaction.execute(...)?;) and if updated == 0 return an appropriate error
(e.g., a NotFound/JobNotFound error from your crate) instead of proceeding to
prune_old_jobs or returning success. Apply this check in both complete_job (the
UPDATE that sets status = Succeeded) and fail_job (the UPDATE that sets status =
Failed) before calling prune_old_jobs(transaction) or committing.

---

Outside diff comments:
In `@crates/daemon/src/lib.rs`:
- Around line 43-48: The current code uses ? on self.task.await and on
task_result which short-circuits and skips socket cleanup; change the flow in
the functions using self.task.await and state::fs::remove_daemon_socket so you
first capture the task join result without bubbling it (let task_result =
self.task.await), then always call state::fs::remove_daemon_socket(&self.paths)
to get socket_result, and only after the removal propagate errors (e.g. return
task_result?; socket_result? or prefer a combined/error-prioritizing strategy);
update the code paths that reference task_result and socket_result (the await
and the remove_daemon_socket calls) so socket cleanup runs even when the task
join returns Err.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 972ab312-39ba-4468-b49e-10688d557406

📥 Commits

Reviewing files that changed from the base of the PR and between efcd209 and f5545fe.

⛔ Files ignored due to path filters (7)
  • Cargo.lock is excluded by !**/*.lock
  • crates/daemon/tests/snapshots/daemon_foundation__disconnected_job_stream_still_persists_final_status.snap is excluded by !**/*.snap
  • crates/daemon/tests/snapshots/daemon_foundation__idle_client_without_newline_does_not_block_health_requests.snap is excluded by !**/*.snap
  • crates/daemon/tests/snapshots/daemon_foundation__socket_protocol_streams_job_progress_and_persists_final_status.snap is excluded by !**/*.snap
  • crates/daemon/tests/snapshots/daemon_foundation__start_removes_stale_socket_before_binding.snap is excluded by !**/*.snap
  • crates/daemon/tests/snapshots/daemon_foundation__unsupported_job_streams_failure_event_and_persists_failed_status.snap is excluded by !**/*.snap
  • crates/state/tests/snapshots/state_foundation__recent_jobs_returns_the_latest_one_hundred_jobs.snap is excluded by !**/*.snap
📒 Files selected for processing (12)
  • Cargo.toml
  • crates/daemon/Cargo.toml
  • crates/daemon/src/error.rs
  • crates/daemon/src/jobs.rs
  • crates/daemon/src/lib.rs
  • crates/daemon/src/protocol.rs
  • crates/daemon/src/server.rs
  • crates/daemon/tests/daemon_foundation.rs
  • crates/state/src/database.rs
  • crates/state/src/error.rs
  • crates/state/src/lib.rs
  • crates/state/tests/state_foundation.rs
✅ Files skipped from review due to trivial changes (1)
  • crates/daemon/Cargo.toml

Comment thread crates/daemon/src/server.rs
Comment thread crates/daemon/src/server.rs Outdated
Comment thread crates/daemon/tests/daemon_foundation.rs
Comment thread crates/state/src/database.rs Outdated
@munezaclovis
munezaclovis merged commit 5bc8cd8 into main May 24, 2026
2 checks passed
@munezaclovis
munezaclovis deleted the feat/daemon-foundation branch May 24, 2026 20:32
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