Skip to content

fix(attachment): use raw content hash to prevent false external-change warnings#2534

Merged
tusharmath merged 6 commits intomainfrom
fix-attachment-change-detection
Mar 12, 2026
Merged

fix(attachment): use raw content hash to prevent false external-change warnings#2534
tusharmath merged 6 commits intomainfrom
fix-attachment-change-detection

Conversation

@tusharmath
Copy link
Copy Markdown
Collaborator

@tusharmath tusharmath commented Mar 12, 2026

Summary

Fix false "modified externally" warnings caused by a hash mismatch between the line-numbered content stored in metrics and the raw file content read back from disk during external-change detection.

Context

When a file attachment was created, the content hash was computed after line numbers were prepended to each line (e.g. 1:content\n2:more\n). The external-change detector later hashed the raw file bytes from disk — without line numbers — so the two hashes never matched, triggering spurious "file modified externally" warnings on every turn even when the file had not changed.

Changes

  • Added a content_hash field to AttachmentContent::FileContent that stores the SHA-256 hash of the raw (unformatted, untruncated) file content, computed before line-numbering is applied
  • Updated AttachmentService to compute and store this raw hash at attachment creation time
  • Updated UserPromptGenerator to read the pre-computed content_hash from the attachment instead of re-hashing the already-formatted content
  • Refactored RateLimiter to use interior mutability (Mutex<State>) so it no longer requires &mut self, allowing it to be stored as Arc<RateLimiter> without an outer Mutex
  • Simplified context_engine.rs by inlining the walk_directory helper and removing the empty-git-ls-files fallback branch (an empty list is now treated as a valid result)
  • Cleaned up built-in commands: renamed config-providerprovider and config-modelmodel, removed the standalone config command and its shell-plugin handler

Key Implementation Details

The root cause was a two-step process:

  1. AttachmentService read the raw file bytes, then formatted them with line numbers via to_numbered_from()
  2. UserPromptGenerator hashed the already-formatted string and stored it as the "last seen" hash
  3. The external-change detector hashed the raw file — producing a different digest — and always flagged a change

The fix moves hash computation to step 1 (before formatting) and threads the raw hash through AttachmentContent::FileContent so step 2 can store the correct value.

Testing

# Run all tests with snapshot acceptance
cargo insta test --accept

# Verify the attachment service tests pass (they now assert the correct raw hash)
cargo test -p forge_services attachment

# Verify context engine and user_prompt tests pass
cargo test -p forge_app user_prompt
cargo test -p forge_domain context

Links

  • Related to false external-change warning behaviour in the context engine

@github-actions github-actions Bot added the type: fix Iterations on existing features or infrastructure. label Mar 12, 2026
@tusharmath tusharmath enabled auto-merge (squash) March 12, 2026 08:33
@tusharmath tusharmath merged commit 70cba43 into main Mar 12, 2026
9 checks passed
@tusharmath tusharmath deleted the fix-attachment-change-detection branch March 12, 2026 08:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: fix Iterations on existing features or infrastructure.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant