fix(state): fix Errored(None) producing invalid TOML state file#231
fix(state): fix Errored(None) producing invalid TOML state file#231
Conversation
`DaemonStatus::Errored(Option<i32>)` with `None` serialized to an empty TOML table `[status]` because TOML has no null representation. This caused parse errors when reading the state file back, losing all daemon state and causing flaky test failures. Change `Errored(Option<i32>)` to `Errored(i32)` using -1 as sentinel for unknown exit codes. Add TOML roundtrip test to prevent regression. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary of ChangesHello @jdx, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request addresses a critical bug where daemon state files, when containing an Highlights
Changelog
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Pull request overview
Fixes invalid TOML state serialization for DaemonStatus::Errored when the exit code is unknown by replacing Option<i32> with a sentinel i32 value and adding a regression test for TOML round-tripping.
Changes:
- Change
DaemonStatus::Errored(Option<i32>)toDaemonStatus::Errored(i32)with-1meaning “unknown exit code”. - Update UI + supervisor lifecycle code paths to use/display the new sentinel value.
- Add TOML roundtrip test to prevent regressions in state file serialization.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/tui/ui.rs | Updates status display logic to hide sentinel/unknown exit codes. |
| src/supervisor/lifecycle.rs | Writes Errored(-1) when an exit code is unavailable. |
| src/daemon_status.rs | Updates enum + error message formatting and adds TOML roundtrip test. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| #[test] | ||
| fn test_daemon_status_toml_roundtrip() { | ||
| #[derive(Serialize, Deserialize, Debug)] | ||
| struct Wrapper { | ||
| status: DaemonStatus, | ||
| } |
There was a problem hiding this comment.
#[derive(Serialize, Deserialize)] requires Serialize/Deserialize to be in scope inside mod tests. Since use items from the parent module don’t automatically carry into child modules, this can fail to compile. Fix by importing serde::{Serialize, Deserialize} within mod tests, or by qualifying the derives as #[derive(serde::Serialize, serde::Deserialize, Debug)].
| Some(code) => DaemonStatus::Errored(code), | ||
| None => DaemonStatus::Errored(-1), |
There was a problem hiding this comment.
-1 is a magic number used as a sentinel for “unknown exit code” and is repeated across files (also in UI/tests). Introduce a single shared constant (e.g., DaemonStatus::UNKNOWN_EXIT_CODE or const UNKNOWN_EXIT_CODE: i32 = -1;) and use it everywhere to avoid accidental inconsistencies and make intent explicit.
| #[test] | ||
| fn test_daemon_status_json_roundtrip() { | ||
| let variants = vec - 2026-02-11 ### Fixed - *(state)* fix Errored(None) producing invalid TOML state file ([#231](#231)) </blockquote> </p></details> --- This PR was generated with [release-plz](https://github.com/release-plz/release-plz/). <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Release metadata-only changes (version/changelog/lockfile) with no functional code modifications in this PR. > > **Overview** > Prepares the `v1.4.2` release by bumping `pitchfork-cli` version from `1.4.1` to `1.4.2` in `Cargo.toml`/`Cargo.lock`. > > Updates `CHANGELOG.md` with the `1.4.2` entry noting a state serialization fix for `Errored(None)` producing invalid TOML. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 04df47a. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
Summary
DaemonStatus::Errored(Option<i32>)withNoneserialized to an empty TOML table[status]because TOML has no null representationtest_stop_already_stoppedfailuresErrored(Option<i32>)toErrored(i32)using-1as sentinel for unknown exit codesTest plan
test_daemon_status_toml_roundtriptest passes for all variantstest_daemon_status_json_roundtripstill passestest_stop_already_stoppedshould no longer flake🤖 Generated with Claude Code
Note
Low Risk
Small, localized state-model change plus formatting/test updates; primary risk is backward compatibility when deserializing previously persisted state files.
Overview
Fixes daemon state persistence by changing
DaemonStatus::ErroredfromOption<i32>to ani32exit code using-1to represent an unknown code, avoiding invalid TOML output.Updates lifecycle monitoring and TUI status/error rendering to treat
-1as “unknown”, and adds a TOML serialize/deserialize roundtrip test alongside the existing JSON roundtrip to prevent regression.Written by Cursor Bugbot for commit d4acc2c. This will update automatically on new commits. Configure here.