Skip to content

🧹 Janitor: Refactor normalization checks to use is_canonical - #304

Open
matta wants to merge 1 commit into
mainfrom
janitor/is-canonical-refactor-11351538777178646300
Open

🧹 Janitor: Refactor normalization checks to use is_canonical#304
matta wants to merge 1 commit into
mainfrom
janitor/is-canonical-refactor-11351538777178646300

Conversation

@matta

@matta matta commented Mar 17, 2026

Copy link
Copy Markdown
Owner

📉 Diff: +11 lines, -13 lines
🎯 Goal: Common APIs (Factoring common logic into modular APIs)
💡 Before: Both pebble check and pebble check --fix commands manually read the file from disk (fs::read_to_string), manually generated the canonical content (get_content_for_disk), and manually compared them to determine if a formatting error or extra newline existed.
✨ After: A single cohesive is_canonical() method is introduced on TaskNode. Both commands simply call node.is_canonical().is_ok_and(|canonical| !canonical) to determine if normalization is needed, short-circuiting errors automatically.
✅ Verification: just check and just test pass correctly. Code has been reviewed and passes.


PR created automatically by Jules for task 11351538777178646300 started by @matta

Replaced duplicated logic for checking file normalization (comparing disk
content to canonical generated content) in `commands_diagnostics.rs` and
`commands_fix.rs` with a single, modular `is_canonical()` API on `TaskNode`.

Co-authored-by: matta <37314+matta@users.noreply.github.com>
@google-labs-jules

Copy link
Copy Markdown
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@trunk-io

trunk-io Bot commented Mar 17, 2026

Copy link
Copy Markdown
Contributor

Merging to main in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, 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 streamlines the process of verifying and fixing canonical task file content within the pebble tool. By introducing a dedicated is_canonical() method, it abstracts away the low-level file I/O and content generation, leading to more modular, readable, and maintainable code for normalization checks across different commands.

Highlights

  • Refactor normalization checks: The manual process of reading file content and comparing it to canonical content in pebble check and pebble check --fix has been replaced. A new is_canonical() method on TaskNode now centralizes this logic, simplifying the check for normalization needs.
Changelog
  • crates/pebble/src/commands_diagnostics.rs
    • Removed the direct import of std::fs.
    • Replaced the manual file content comparison with a call to node.is_canonical().
  • crates/pebble/src/commands_fix.rs
    • Removed the direct import of std::fs.
    • Replaced the manual file content comparison with a call to node.is_canonical().
  • crates/pebble/src/models.rs
    • Added a new public method is_canonical() to the TaskNode struct, which checks if the file's disk content matches its canonical format.
    • Updated the documentation for the write_to_disk() method to reflect its purpose of writing canonical content.
Activity
  • PR was automatically created by Jules for task 11351538777178646300, started by @matta.
  • Code has been reviewed and passes.
  • Verification steps just check and just test passed correctly.
Using Gemini Code Assist

The 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 /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

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 .gemini/ folder in the base of the repository. Detailed instructions can be found here.

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

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

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.

Code Review

This pull request refactors the logic for checking if task files are in their canonical format by introducing a new is_canonical method on TaskNode, which is subsequently used in the diagnostics and fix commands. Review feedback indicates that the is_ok_and usage in commands_fix.rs could silently ignore errors from is_canonical, which should instead be propagated to ensure proper error handling. Additionally, the is_canonical method currently re-reads files from disk, potentially causing a performance bottleneck, and suggests caching file content on TaskNode as a future optimization.

Comment on lines +65 to 67
if node.is_canonical().is_ok_and(|canonical| !canonical) {
modified = true;
}

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.

high

Using is_ok_and here causes errors from node.is_canonical() to be silently ignored. If checking for canonical content fails (e.g., due to an I/O or serialization error), repair_node will incorrectly return Ok(false), suggesting no modification was needed and no error occurred. The error should be propagated up so the fix command fails, indicating that it couldn't complete the repair.

Suggested change
if node.is_canonical().is_ok_and(|canonical| !canonical) {
modified = true;
}
if !node.is_canonical()? {
modified = true;
}

Comment on lines +354 to +358
pub fn is_canonical(&self) -> Result<bool> {
let disk_content = fs::read_to_string(&self.path)?;
let canonical_content = self.get_content_for_disk()?;
Ok(disk_content == canonical_content)
}

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.

medium

This is a great refactoring to centralize the canonical check. However, this implementation reads the file from disk via fs::read_to_string. Since the TaskNode is created by loading the graph, which involves reading the task files, this results in each file being read from disk a second time. This could be a performance bottleneck with a large number of tasks.

A more efficient approach would be to cache the raw file content on the TaskNode during the initial load. is_canonical could then perform the comparison without a redundant file I/O operation.

While implementing this would require changes in the file parsing logic outside of this function, it's a valuable future optimization to consider. For example:

// In TaskNode struct, you could add:
// pub raw_content: String,

// Then is_canonical could be changed to:
pub fn is_canonical(&self) -> Result<bool> {
    let canonical_content = self.get_content_for_disk()?;
    Ok(self.raw_content == canonical_content)
}

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