From 1c0fc21d441cff37cc53375cb575b91f91aabb8f Mon Sep 17 00:00:00 2001 From: Alexey Nikandrov Date: Mon, 31 Aug 2026 10:02:56 +0300 Subject: [PATCH] fix: make `list` strictly read-only, stop rewriting .index.json The `list` command called `refresh_index`, which unconditionally wrote `docs/rfcs/.index.json` on every invocation (re-serialize + fs::write), changing the file's mtime and content even when nothing had changed. Extract the scanning logic into `refresh_entries`, returning a `dirty` flag. `refresh_index` now persists only when a real change is detected, and a new `refresh_index_readonly` performs an in-memory refresh without touching disk. `list` uses the read-only variant. Bump version to 0.1.5 and document the fix in CHANGELOG. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- CHANGELOG.md | 7 +++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- src/commands/list.rs | 2 +- src/rfclib/index.rs | 31 ++++++++++++++++++++++++++----- 5 files changed, 36 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ef3151..db167fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to this project are documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.1.5] + +### Fixed +- `list` is now strictly read-only and no longer rewrites `docs/rfcs/.index.json` + on every invocation. The index is persisted only when a real change is + detected during refresh. + ## [0.1.4] ### Added diff --git a/Cargo.lock b/Cargo.lock index d5e0d0d..4ffc752 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -239,7 +239,7 @@ dependencies = [ [[package]] name = "rfc-cli" -version = "0.1.4" +version = "0.1.5" dependencies = [ "clap", "clap_builder", diff --git a/Cargo.toml b/Cargo.toml index 7d1e519..6de0ae1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rfc-cli" -version = "0.1.4" +version = "0.1.5" edition = "2021" [dependencies] diff --git a/src/commands/list.rs b/src/commands/list.rs index 85c9d0c..fc94b64 100644 --- a/src/commands/list.rs +++ b/src/commands/list.rs @@ -5,7 +5,7 @@ use crate::rfclib::index; /// Executes the `list` command: shows table of all RFCs pub fn execute(project_root: &Path, status_filter: Option<&str>) -> Result<(), String> { let mut idx = index::load_index(project_root)?; - index::refresh_index(project_root, &mut idx)?; + index::refresh_index_readonly(project_root, &mut idx)?; let mut rfcs: Vec<&index::IndexEntry> = idx.rfcs.iter().collect(); diff --git a/src/rfclib/index.rs b/src/rfclib/index.rs index 12740b7..72a9733 100644 --- a/src/rfclib/index.rs +++ b/src/rfclib/index.rs @@ -65,12 +65,31 @@ pub fn compute_content_hash(content: &str) -> String { /// Refreshes index: compares mtime of files with index entries, /// reparses changed ones, adds new ones, removes stale ones. +/// Persists the index to disk only if any change was detected. pub fn refresh_index(project_root: &Path, index: &mut Index) -> Result<(), String> { + let dirty = refresh_entries(project_root, index)?; + if dirty { + save_index(project_root, index)?; + } + Ok(()) +} + +/// Refreshes the in-memory index without ever writing to disk. Read-only. +pub fn refresh_index_readonly(project_root: &Path, index: &mut Index) -> Result<(), String> { + refresh_entries(project_root, index)?; + Ok(()) +} + +/// Scans RFC files and updates the in-memory index, returning `true` if the +/// index changed. Never writes to disk. +fn refresh_entries(project_root: &Path, index: &mut Index) -> Result { let rfcs_dir = project_root.join("docs/rfcs"); if !rfcs_dir.exists() { - return Ok(()); + return Ok(false); } + let mut dirty = false; + // Scan all .md files in docs/rfcs/ let mut found_numbers: Vec = Vec::new(); let entries = fs::read_dir(&rfcs_dir) @@ -148,19 +167,21 @@ pub fn refresh_index(project_root: &Path, index: &mut Index) -> Result<(), Strin // Remove old entry if exists, then add new one index.rfcs.retain(|e| e.number != number); index.rfcs.push(new_entry); + dirty = true; } } // Remove entries for which files no longer exist + let before = index.rfcs.len(); index.rfcs.retain(|e| found_numbers.contains(&e.number)); + if index.rfcs.len() != before { + dirty = true; + } // Sort by number index.rfcs.sort_by(|a, b| a.number.cmp(&b.number)); - // Save - save_index(project_root, index)?; - - Ok(()) + Ok(dirty) } /// Completely rebuilds the index from scratch by scanning all RFC files.