🦀 Rust Guard Improvement Report
Improvement 1: Remove Write-Only repo_owner_type_cache
Category: Dead Code
File(s): guards/github-guard/rust-guard/src/labels/backend.rs
Effort: Small (< 15 min)
Risk: Low
Problem
backend.rs maintains three process-wide static caches, but only two are ever read. The owner-type cache (repo_owner_type_cache, line 22) is written to on every is_repo_private_with_callback call via set_cached_owner_is_org (line 63), yet there is no corresponding get_cached_owner_is_org reader anywhere in the codebase. Every is_repo_private_with_callback invocation:
- Locks the
Mutex to write an entry (wasted Mutex acquisition)
- Grows the
HashMap indefinitely over the process lifetime (wasted memory)
- Keeps dead functions (
repo_owner_type_cache, set_cached_owner_is_org) around for no benefit
This is a classic incomplete-feature footgun: the infrastructure was added in anticipation of a reader that was never wired up.
Suggested Change
Remove repo_owner_type_cache, set_cached_owner_is_org, and the call site inside is_repo_private_with_callback. Preserve the debug log by retaining extract_owner_is_org inline (no allocation needed), or drop the whole block if the log is not valuable.
Before
// backend.rs lines 22-26
fn repo_owner_type_cache() -> &'static Mutex<HashMap<String, bool>> {
static CACHE: OnceLock<Mutex<HashMap<String, bool>>> = OnceLock::new();
CACHE.get_or_init(|| Mutex::new(HashMap::new()))
}
// lines 63-67
fn set_cached_owner_is_org(repo_id: &str, is_org: bool) {
if let Ok(mut cache) = repo_owner_type_cache().lock() {
cache.insert(repo_id.to_string(), is_org);
}
}
// lines 222-229 (inside is_repo_private_with_callback)
if let Some(is_org) = extract_owner_is_org(&response, &repo_id) {
set_cached_owner_is_org(&repo_id, is_org);
crate::log_debug(&format!(
"Repo owner type for {}: {}",
repo_id,
if is_org { "Organization" } else { "User" }
));
}
After
// Remove repo_owner_type_cache and set_cached_owner_is_org entirely.
// lines 222-229 (inside is_repo_private_with_callback) — keep log, drop cache write
if let Some(is_org) = extract_owner_is_org(&response, &repo_id) {
crate::log_debug(&format!(
"Repo owner type for {}: {}",
repo_id,
if is_org { "Organization" } else { "User" }
));
}
Why This Matters
In WASM, heap is a finite shared resource. A HashMap that grows without bound and is never consulted wastes both memory and Mutex lock cycles on every repo-visibility check. Removing it eliminates dead code and tightens the module's invariant: every static cache has both a writer and a reader.
Improvement 2: Delegate get_issue_author_association_with_callback to get_issue_author_info_with_callback
Category: Duplication
File(s): guards/github-guard/rust-guard/src/labels/backend.rs
Effort: Small (< 15 min)
Risk: Low
Problem
get_issue_author_association_with_callback (lines 344–391) is a strict subset of get_issue_author_info_with_callback (lines 393–450). Both functions:
- Validate the same three inputs (
owner, repo, issue_number)
- Construct the same JSON args (
owner, repo, issue_number, method: "get")
- Allocate the same
SMALL_BUFFER_SIZE buffer
- Call the same backend tool (
"issue_read")
- Parse the response via identical UTF-8 → JSON →
extract_mcp_response chain
- Extract
author_association via the same two-field fallback (author_association / authorAssociation)
The only difference is that get_issue_author_info_with_callback also extracts author_login. This 35-line duplication means any future change to the issue_read call shape (error handling, buffer size, field names) must be applied in two places.
Suggested Change
Replace the full implementation of get_issue_author_association_with_callback with a one-line delegate to get_issue_author_info_with_callback.
Before
// backend.rs lines 344–391
pub fn get_issue_author_association_with_callback(
callback: GithubMcpCallback,
owner: &str,
repo: &str,
issue_number: &str,
) -> Option<String> {
if owner.is_empty() || repo.is_empty() || issue_number.is_empty() {
return None;
}
let args = serde_json::json!({
"owner": owner,
"repo": repo,
"issue_number": issue_number,
"method": "get",
});
let args_str = args.to_string();
let mut result_buffer = vec![0u8; SMALL_BUFFER_SIZE];
let len = match callback("issue_read", &args_str, &mut result_buffer) {
Ok(len) if len > 0 => len,
_ => return None,
};
let response_str = std::str::from_utf8(&result_buffer[..len]).ok()?;
let response = serde_json::from_str::<Value>(response_str).ok()?;
let issue = super::extract_mcp_response(&response);
issue
.get("author_association")
.or_else(|| issue.get("authorAssociation"))
.and_then(|v| v.as_str())
.map(String::from)
}
After
pub fn get_issue_author_association_with_callback(
callback: GithubMcpCallback,
owner: &str,
repo: &str,
issue_number: &str,
) -> Option<String> {
get_issue_author_info_with_callback(callback, owner, repo, issue_number)
.and_then(|info| info.author_association)
}
Why This Matters
This turns 35 lines into 3 and makes the single source of truth explicit. The call site in helpers.rs (line 1591) continues to call get_issue_author_association unchanged — only the internal implementation is simplified. Future changes to the issue_read fetch path need to be made in exactly one place.
Codebase Health Summary
- Total Rust files: 9
- Total lines: 12,832
- Areas analyzed:
backend.rs, constants.rs, tools.rs, helpers.rs, lib.rs, mod.rs, response_paths.rs, response_items.rs, tool_rules.rs
- Areas with no further improvements: none identified yet
Generated by Rust Guard Improver • Run: §24771359121
Generated by Rust Guard Improver · ● 1.3M · ◷
🦀 Rust Guard Improvement Report
Improvement 1: Remove Write-Only
repo_owner_type_cacheCategory: Dead Code
File(s):
guards/github-guard/rust-guard/src/labels/backend.rsEffort: Small (< 15 min)
Risk: Low
Problem
backend.rsmaintains three process-wide static caches, but only two are ever read. The owner-type cache (repo_owner_type_cache, line 22) is written to on everyis_repo_private_with_callbackcall viaset_cached_owner_is_org(line 63), yet there is no correspondingget_cached_owner_is_orgreader anywhere in the codebase. Everyis_repo_private_with_callbackinvocation:Mutexto write an entry (wastedMutexacquisition)HashMapindefinitely over the process lifetime (wasted memory)repo_owner_type_cache,set_cached_owner_is_org) around for no benefitThis is a classic incomplete-feature footgun: the infrastructure was added in anticipation of a reader that was never wired up.
Suggested Change
Remove
repo_owner_type_cache,set_cached_owner_is_org, and the call site insideis_repo_private_with_callback. Preserve the debug log by retainingextract_owner_is_orginline (no allocation needed), or drop the whole block if the log is not valuable.Before
After
Why This Matters
In WASM, heap is a finite shared resource. A
HashMapthat grows without bound and is never consulted wastes both memory andMutexlock cycles on every repo-visibility check. Removing it eliminates dead code and tightens the module's invariant: every static cache has both a writer and a reader.Improvement 2: Delegate
get_issue_author_association_with_callbacktoget_issue_author_info_with_callbackCategory: Duplication
File(s):
guards/github-guard/rust-guard/src/labels/backend.rsEffort: Small (< 15 min)
Risk: Low
Problem
get_issue_author_association_with_callback(lines 344–391) is a strict subset ofget_issue_author_info_with_callback(lines 393–450). Both functions:owner,repo,issue_number)owner,repo,issue_number,method: "get")SMALL_BUFFER_SIZEbuffer"issue_read")extract_mcp_responsechainauthor_associationvia the same two-field fallback (author_association/authorAssociation)The only difference is that
get_issue_author_info_with_callbackalso extractsauthor_login. This 35-line duplication means any future change to theissue_readcall shape (error handling, buffer size, field names) must be applied in two places.Suggested Change
Replace the full implementation of
get_issue_author_association_with_callbackwith a one-line delegate toget_issue_author_info_with_callback.Before
After
Why This Matters
This turns 35 lines into 3 and makes the single source of truth explicit. The call site in
helpers.rs(line 1591) continues to callget_issue_author_associationunchanged — only the internal implementation is simplified. Future changes to theissue_readfetch path need to be made in exactly one place.Codebase Health Summary
backend.rs,constants.rs,tools.rs,helpers.rs,lib.rs,mod.rs,response_paths.rs,response_items.rs,tool_rules.rsGenerated by Rust Guard Improver • Run: §24771359121